@zango-core/appbuilder 1.0.0-rc.1
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/ConfigurePage-DRzSb06z.js +29 -0
- package/dist/ConfigurePage-DRzSb06z.js.map +1 -0
- package/dist/LoginPageWithRoleSelection-xTr_eIWh.js +662 -0
- package/dist/LoginPageWithRoleSelection-xTr_eIWh.js.map +1 -0
- package/dist/PageTypeRegistry-5269IpiS.js +53 -0
- package/dist/PageTypeRegistry-5269IpiS.js.map +1 -0
- package/dist/index.framework-B8SMzgN1.js +28005 -0
- package/dist/index.framework-B8SMzgN1.js.map +1 -0
- package/dist/types/App.d.ts +14 -0
- package/dist/types/__tests__/mocks/data/appInitData.d.ts +197 -0
- package/dist/types/__tests__/mocks/data/authConfigData.d.ts +356 -0
- package/dist/types/__tests__/mocks/externalPackages.d.ts +42 -0
- package/dist/types/__tests__/mocks/handlers/appInit.handlers.d.ts +3 -0
- package/dist/types/__tests__/mocks/handlers/auth.handlers.d.ts +1 -0
- package/dist/types/__tests__/mocks/handlers/index.d.ts +5 -0
- package/dist/types/__tests__/mocks/handlers/profile.handlers.d.ts +15 -0
- package/dist/types/__tests__/mocks/handlers/session.handlers.d.ts +2 -0
- package/dist/types/__tests__/setup/setupDOMMatchers.d.ts +0 -0
- package/dist/types/__tests__/setup/setupMSW.d.ts +1 -0
- package/dist/types/__tests__/setup/setupTests.d.ts +34 -0
- package/dist/types/__tests__/utils/mockRouterUtils.d.ts +62 -0
- package/dist/types/__tests__/utils/renderWithProviders.d.ts +22 -0
- package/dist/types/__tests__/utils/waitForHelpers.d.ts +36 -0
- package/dist/types/auth/components/AuthMobileShell.d.ts +8 -0
- package/dist/types/auth/components/AuthProvider.d.ts +30 -0
- package/dist/types/auth/components/DynamicLoginForm.d.ts +9 -0
- package/dist/types/auth/components/ForgotPasswordForm.d.ts +11 -0
- package/dist/types/auth/components/LoginForm.d.ts +7 -0
- package/dist/types/auth/components/LoginRouter.d.ts +197 -0
- package/dist/types/auth/components/OAuthCallback.d.ts +19 -0
- package/dist/types/auth/components/OTPForm.d.ts +11 -0
- package/dist/types/auth/components/OTPInput.d.ts +8 -0
- package/dist/types/auth/components/PasswordResetRequired.d.ts +23 -0
- package/dist/types/auth/components/ProviderButton.d.ts +17 -0
- package/dist/types/auth/components/ResetPasswordForm.d.ts +12 -0
- package/dist/types/auth/components/RoleSelection.d.ts +25 -0
- package/dist/types/auth/components/SecondFactorAuth.d.ts +21 -0
- package/dist/types/auth/components/composable/OTPLoginForm.d.ts +17 -0
- package/dist/types/auth/components/composable/PasswordLoginForm.d.ts +17 -0
- package/dist/types/auth/components/composable/SSOButtons.d.ts +61 -0
- package/dist/types/auth/components/composable/index.d.ts +42 -0
- package/dist/types/auth/contexts/LoginContext.d.ts +6 -0
- package/dist/types/auth/hocs/withMultiStepAuth.d.ts +35 -0
- package/dist/types/auth/index.d.ts +23 -0
- package/dist/types/auth/pages/CompleteAuthFlow.d.ts +24 -0
- package/dist/types/auth/pages/LoginPage.d.ts +8 -0
- package/dist/types/auth/pages/LoginPageWithRoleSelection.d.ts +13 -0
- package/dist/types/auth/pages/OAuthCallbackPage.d.ts +17 -0
- package/dist/types/auth/pages/SAMLCallbackPage.d.ts +16 -0
- package/dist/types/auth/services/authService.d.ts +87 -0
- package/dist/types/auth/services/internal/apiClients.d.ts +9 -0
- package/dist/types/auth/services/internal/authState.d.ts +12 -0
- package/dist/types/auth/services/internal/errorHelper.d.ts +1 -0
- package/dist/types/auth/services/internal/oauthSamlService.d.ts +46 -0
- package/dist/types/auth/services/internal/passwordValidator.d.ts +17 -0
- package/dist/types/auth/services/network/api.d.ts +1629 -0
- package/dist/types/auth/services/network/base.d.ts +31 -0
- package/dist/types/auth/services/network/configuration.d.ts +74 -0
- package/dist/types/auth/services/network/index.d.ts +13 -0
- package/dist/types/auth/stores/index.d.ts +1 -0
- package/dist/types/auth/stores/useAuthStore.d.ts +6 -0
- package/dist/types/auth/types/index.d.ts +57 -0
- package/dist/types/auth/utils/authFlowHandler.d.ts +72 -0
- package/dist/types/auth/utils/authUtils.d.ts +21 -0
- package/dist/types/auth/utils/validators.d.ts +18 -0
- package/dist/types/components/ErrorBoundary.d.ts +23 -0
- package/dist/types/components/ErrorFallback.d.ts +8 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/components/ui/avatar.d.ts +11 -0
- package/dist/types/components/ui/button.d.ts +10 -0
- package/dist/types/components/ui/collapsible.d.ts +5 -0
- package/dist/types/components/ui/dialog.d.ts +13 -0
- package/dist/types/components/ui/dropdown-menu.d.ts +10 -0
- package/dist/types/components/ui/empty.d.ts +8 -0
- package/dist/types/components/ui/index.d.ts +12 -0
- package/dist/types/components/ui/input.d.ts +3 -0
- package/dist/types/components/ui/separator.d.ts +4 -0
- package/dist/types/components/ui/sheet.d.ts +14 -0
- package/dist/types/components/ui/sidebar.d.ts +69 -0
- package/dist/types/components/ui/skeleton.d.ts +2 -0
- package/dist/types/components/ui/tooltip.d.ts +7 -0
- package/dist/types/framework/ZangoApp.d.ts +19 -0
- package/dist/types/framework/components/CachedLogo.d.ts +9 -0
- package/dist/types/framework/components/CustomPageFallback.d.ts +13 -0
- package/dist/types/framework/components/CustomPageLoader.d.ts +10 -0
- package/dist/types/framework/components/DocumentHead.d.ts +5 -0
- package/dist/types/framework/components/RouteErrorBoundary.d.ts +16 -0
- package/dist/types/framework/components/SessionSecurityDialog.d.ts +10 -0
- package/dist/types/framework/components/SessionSecurityProvider.d.ts +8 -0
- package/dist/types/framework/components/SmartLink.d.ts +13 -0
- package/dist/types/framework/components/layout/AppSidebar.d.ts +36 -0
- package/dist/types/framework/components/layout/Breadcrumbs.d.ts +2 -0
- package/dist/types/framework/components/layout/CommandPalette.d.ts +2 -0
- package/dist/types/framework/components/layout/Layout.d.ts +2 -0
- package/dist/types/framework/components/layout/Navbar.d.ts +9 -0
- package/dist/types/framework/components/layout/NavbarIcon.d.ts +12 -0
- package/dist/types/framework/components/layout/Topbar.d.ts +50 -0
- package/dist/types/framework/components/layout/UserProfileDrawer.d.ts +7 -0
- package/dist/types/framework/components/layout/profile/PasswordCard.d.ts +18 -0
- package/dist/types/framework/components/layout/profile/PersonalInfoCard.d.ts +12 -0
- package/dist/types/framework/components/layout/profile/ProfileRail.d.ts +23 -0
- package/dist/types/framework/components/layout/profile/SessionsCard.d.ts +8 -0
- package/dist/types/framework/components/layout/profile/TokensCard.d.ts +11 -0
- package/dist/types/framework/components/layout/profile/TwoFactorCard.d.ts +7 -0
- package/dist/types/framework/config/defaultLayoutConfig.d.ts +34 -0
- package/dist/types/framework/constants/routes.d.ts +5 -0
- package/dist/types/framework/contexts/AppContext.d.ts +57 -0
- package/dist/types/framework/contexts/AuthConfigContext.d.ts +22 -0
- package/dist/types/framework/hooks/useProfileData.d.ts +73 -0
- package/dist/types/framework/hooks/useRoutes.d.ts +10 -0
- package/dist/types/framework/hooks/useSessionSecurity.d.ts +17 -0
- package/dist/types/framework/hooks/useSmartNavigation.d.ts +15 -0
- package/dist/types/framework/index.d.ts +35 -0
- package/dist/types/framework/pages/ConfigurePage.d.ts +2 -0
- package/dist/types/framework/pages/CrudPage.d.ts +6 -0
- package/dist/types/framework/pages/LoginPage.d.ts +5 -0
- package/dist/types/framework/pages/LogoutPage.d.ts +2 -0
- package/dist/types/framework/pages/NotFoundPage.d.ts +6 -0
- package/dist/types/framework/pages/TrainingPage.d.ts +6 -0
- package/dist/types/framework/routing/PageTypeRegistry.d.ts +43 -0
- package/dist/types/framework/routing/PageTypeRouter.d.ts +12 -0
- package/dist/types/framework/routing/dynamicPageRegistry.d.ts +41 -0
- package/dist/types/framework/routing/getRenderComponent.d.ts +6 -0
- package/dist/types/framework/types/layout.types.d.ts +107 -0
- package/dist/types/framework/utils/apiConfig.d.ts +41 -0
- package/dist/types/framework/utils/apiInterceptor.d.ts +12 -0
- package/dist/types/framework/utils/apiUrlUtils.d.ts +9 -0
- package/dist/types/framework/utils/authThemeUtils.d.ts +64 -0
- package/dist/types/framework/utils/colorUtils.d.ts +53 -0
- package/dist/types/framework/utils/cookieUtils.d.ts +20 -0
- package/dist/types/framework/utils/csrf.d.ts +27 -0
- package/dist/types/framework/utils/logoCache.d.ts +21 -0
- package/dist/types/framework/utils/logoutUtils.d.ts +15 -0
- package/dist/types/framework/utils/redirectUtils.d.ts +48 -0
- package/dist/types/framework/utils/safeRedirect.d.ts +21 -0
- package/dist/types/framework/utils/storageKeys.d.ts +44 -0
- package/dist/types/framework/utils/storageSanitizer.d.ts +20 -0
- package/dist/types/hooks/index.d.ts +2 -0
- package/dist/types/hooks/queries/index.d.ts +4 -0
- package/dist/types/hooks/queries/useAppInitQuery.d.ts +1 -0
- package/dist/types/hooks/queries/useAuthConfigQuery.d.ts +1 -0
- package/dist/types/hooks/queries/useProfileQuery.d.ts +8 -0
- package/dist/types/hooks/useBreakpoint.d.ts +2 -0
- package/dist/types/hooks/useMobile.d.ts +1 -0
- package/dist/types/index.d.ts +0 -0
- package/dist/types/index.framework.d.ts +39 -0
- package/dist/types/index.zango.d.ts +12 -0
- package/dist/types/lib/index.d.ts +1 -0
- package/dist/types/lib/utils.d.ts +2 -0
- package/dist/types/schemas/appInit.schema.d.ts +61 -0
- package/dist/types/schemas/index.d.ts +10 -0
- package/dist/types/schemas/profile.schema.d.ts +18 -0
- package/dist/types/schemas/route.schema.d.ts +9 -0
- package/dist/types/schemas/session.schema.d.ts +8 -0
- package/dist/types/schemas/theme.schema.d.ts +27 -0
- package/dist/types/services/api/index.d.ts +2 -0
- package/dist/types/services/api.d.ts +109 -0
- package/dist/types/services/index.d.ts +7 -0
- package/dist/types/services/legacyAdapter.d.ts +10 -0
- package/dist/types/services/logger.d.ts +32 -0
- package/dist/types/services/normalizeResponse.d.ts +29 -0
- package/dist/types/types/auth.d.ts +103 -0
- package/dist/types/types/common.d.ts +343 -0
- package/dist/types/types/index.d.ts +278 -0
- package/dist/zango-appbuilder.js +99 -0
- package/dist/zango-appbuilder.js.map +1 -0
- package/dist/zango-appbuilder.umd.cjs +247 -0
- package/dist/zango-appbuilder.umd.cjs.map +1 -0
- package/package.json +140 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginPageWithRoleSelection-xTr_eIWh.js","sources":["../src/auth/components/DynamicLoginForm.tsx","../src/auth/components/LoginForm.tsx","../src/auth/pages/LoginPage.tsx","../src/auth/pages/LoginPageWithRoleSelection.tsx"],"sourcesContent":["import {\n Alert,\n Button,\n Checkbox,\n Divider,\n Form,\n FormItem,\n Input,\n PasswordInput,\n Spin,\n Tabs,\n toast,\n} from '@zango-core/components';\nimport { Loader2, Mail, Smartphone } from 'lucide-react';\nimport type React from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { logger } from '@/services/logger';\nimport { useAuthConfig } from '../../framework/contexts/AuthConfigContext';\nimport { getAuthLinkStyle, getAuthSecondaryTextStyle, getAuthTextStyle } from '../../framework/utils/authThemeUtils';\nimport type { AuthProvider as AuthProviderType, AuthResult, LoginCredentials } from '../../types';\nimport { authService } from '../services/authService';\nimport type { AuthResponse } from '../utils/authFlowHandler';\nimport { passwordMinLengthRule } from '../utils/validators';\nimport { useAuthContext } from './AuthProvider';\nimport { OTPForm } from './OTPForm';\nimport { ProviderButton } from './ProviderButton';\n\ninterface DynamicLoginFormProps {\n onLogin: (data: LoginCredentials | AuthResponse) => Promise<void>;\n showRememberMe?: boolean;\n}\n\nexport const DynamicLoginForm: React.FC<DynamicLoginFormProps> = ({ onLogin, showRememberMe = true }) => {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [, setActiveMethod] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<'email' | 'mobile'>('email');\n const [showOTPForm, setShowOTPForm] = useState(false);\n const [formKey, setFormKey] = useState(0); // Use key to reset form\n const [isLoggedIn, setIsLoggedIn] = useState(false);\n const [showPasswordChange, setShowPasswordChange] = useState(false);\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const { authConfig } = useAuthContext();\n const { getLoginConfig, getMessagesConfig, getProvidersConfig, authConfig: configContext } = useAuthConfig();\n\n // Get text styles from authConfig (prefer context config over auth context)\n const effectiveAuthConfig = configContext || authConfig;\n const textStyle = getAuthTextStyle(effectiveAuthConfig);\n const secondaryTextStyle = getAuthSecondaryTextStyle(effectiveAuthConfig);\n const linkStyle = getAuthLinkStyle(effectiveAuthConfig);\n\n // Check if user is authenticated using cookie check (no API call)\n const checkAuthentication = useCallback(async () => {\n try {\n return await authService.isAuthenticated();\n } catch (_error) {\n return false;\n }\n }, []);\n\n useEffect(() => {\n if (authConfig) {\n // Pick the method first: the identifier tabs depend on it. Password and\n // OTP declare their identifiers in different config fields, so seeding\n // the tab from the password usernames on an OTP-only deployment could\n // select an identifier OTP does not accept.\n const defaultMethod = authService.isPasswordLoginEnabled()\n ? 'password'\n : authService.isOTPLoginEnabled()\n ? 'otp'\n : null;\n\n if (defaultMethod) {\n setActiveMethod(defaultMethod);\n }\n\n const allowedUsernames = authService.getAllowedUsernamesForMethod(defaultMethod ?? 'password');\n // Set default tab based on available methods\n if (allowedUsernames && allowedUsernames.length > 0) {\n const hasEmail = allowedUsernames.includes('email');\n const hasMobile = allowedUsernames.includes('mobile');\n if (hasEmail) {\n setActiveTab('email');\n } else if (hasMobile) {\n setActiveTab('mobile');\n }\n }\n }\n }, [authConfig]);\n\n // Check authentication status on mount only (no more polling)\n useEffect(() => {\n const checkSession = async () => {\n const isAuthenticated = await checkAuthentication();\n setIsLoggedIn(isAuthenticated);\n };\n\n checkSession();\n // Removed the setInterval polling - no more repeated API calls\n }, [checkAuthentication]);\n\n if (!authConfig) {\n return (\n <div className=\"flex justify-center items-center min-h-loading-min-h\">\n <Spin size=\"large\" />\n </div>\n );\n }\n\n const getUsernameRules = (type: string) => {\n const messagesConfig = getMessagesConfig();\n\n if (type === 'email') {\n return [\n {\n required: true,\n message: messagesConfig?.validation?.required || 'Please enter your email address',\n },\n {\n type: 'email' as const,\n message: messagesConfig?.validation?.invalidEmail || 'Please enter a valid email address!',\n },\n ];\n }\n if (type === 'mobile') {\n return [\n {\n required: true,\n message: messagesConfig?.validation?.required || 'Please input your mobile number!',\n },\n {\n pattern: /^\\+\\d{7,15}$/,\n message:\n messagesConfig?.validation?.invalidMobile ||\n 'Please enter a valid mobile number with country code (e.g., +919876543210)',\n },\n ];\n }\n // Default to email rules\n return [\n {\n required: true,\n message: messagesConfig?.validation?.required || 'Please enter your email address',\n },\n {\n type: 'email' as const,\n message: messagesConfig?.validation?.invalidEmail || 'Please enter a valid email address!',\n },\n ];\n };\n\n const handleMobileKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n const allowedKeys = ['Backspace', 'Delete', 'Tab', 'Enter', 'ArrowLeft', 'ArrowRight'];\n if (!allowedKeys.includes(e.key) && !e.ctrlKey && !e.metaKey && !/[0-9+]/.test(e.key)) {\n e.preventDefault();\n }\n };\n\n const handlePasswordLogin = async (values: Record<string, unknown>) => {\n setLoading(true);\n setError(null); // Clear any previous errors\n try {\n // Determine which method to use based on activeTab or available methods\n const allowedUsernames = authService.getAllowedUsernames();\n const hasEmail = allowedUsernames.includes('email');\n const hasMobile = allowedUsernames.includes('mobile');\n\n // If only one method is available, use it regardless of activeTab\n const method = hasEmail && hasMobile ? activeTab : hasEmail ? 'email' : 'mobile';\n\n const loginData = {\n email: method === 'email' ? values.username : undefined,\n phone: method === 'mobile' ? values.username : undefined,\n password: values.password,\n remember_me: values.remember || false,\n } as unknown as LoginCredentials;\n\n await onLogin(loginData);\n\n // onLogin will handle the response and next_step processing in CompleteAuthFlow\n } catch (error: unknown) {\n const messagesConfig = getMessagesConfig();\n const errorMessage =\n (error instanceof Error ? error.message : null) ||\n messagesConfig?.errors?.loginFailed ||\n 'Login failed. Please try again.';\n setError(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const handleOTPSuccess = async (result: AuthResult) => {\n await onLogin(result);\n };\n\n const handleLogout = async () => {\n setLoading(true);\n try {\n await authService.logout();\n toast.success('Logged out successfully');\n setIsLoggedIn(false);\n } catch (error: unknown) {\n toast.error(error instanceof Error ? error.message : 'Failed to logout');\n } finally {\n setLoading(false);\n }\n };\n\n const handleChangePassword = async () => {\n if (!newPassword || !confirmPassword) {\n toast.error('Please fill in all password fields');\n return;\n }\n\n if (newPassword !== confirmPassword) {\n toast.error('Passwords do not match');\n return;\n }\n\n if (newPassword.length < 8) {\n toast.error('Password must be at least 8 characters long');\n return;\n }\n\n setLoading(true);\n try {\n await authService.setPassword(newPassword);\n toast.success('Password changed successfully!');\n setShowPasswordChange(false);\n setNewPassword('');\n setConfirmPassword('');\n } catch (error: unknown) {\n toast.error(error instanceof Error ? error.message : 'Failed to change password');\n } finally {\n setLoading(false);\n }\n };\n\n const renderPasswordForm = (type: 'email' | 'mobile') => {\n const loginConfig = getLoginConfig();\n const messagesConfig = getMessagesConfig();\n\n return (\n <Form\n key={`${type}-${formKey}`} // Use key to reset form when switching tabs\n name={`${type}-password-login`}\n className=\"w-full\"\n onFinish={handlePasswordLogin}\n layout=\"vertical\"\n initialValues={{ remember: false }}\n >\n {error && (\n <Alert message={error} type=\"error\" showIcon closable onClose={() => setError(null)} className=\"mb-4\" />\n )}\n\n <FormItem name=\"username\" rules={getUsernameRules(type)}>\n <Input\n placeholder={\n type === 'email'\n ? loginConfig?.formPlaceholders?.email || 'Enter your email address'\n : loginConfig?.formPlaceholders?.mobile || 'Enter your mobile number (+919876543210)'\n }\n autoComplete={type === 'email' ? 'email' : 'tel'}\n onKeyDown={type === 'mobile' ? handleMobileKeyDown : undefined}\n />\n </FormItem>\n\n <FormItem\n name=\"password\"\n rules={[\n {\n required: true,\n // validation.required is worded for the identifier field, so it\n // must not be reused under the password input.\n message: messagesConfig?.validation?.passwordRequired || 'Please input your password!',\n },\n {\n ...passwordMinLengthRule(\n (authConfig?.password_policy ?? null) as Parameters<typeof passwordMinLengthRule>[0],\n ),\n message:\n messagesConfig?.validation?.passwordTooShort ||\n passwordMinLengthRule(\n (authConfig?.password_policy ?? null) as Parameters<typeof passwordMinLengthRule>[0],\n ).message,\n },\n ]}\n >\n <PasswordInput\n placeholder={loginConfig?.formPlaceholders?.password || 'Enter your password'}\n autoComplete=\"current-password\"\n />\n </FormItem>\n\n <FormItem>\n <div className=\"flex justify-between items-center w-full\">\n <div>\n {loginConfig?.showRememberMe !== false && showRememberMe && authService.isRememberMeEnabled() && (\n <FormItem name=\"remember\" valuePropName=\"checked\" noStyle>\n <div className=\"auth-remember-me\" style={secondaryTextStyle}>\n <Checkbox label={loginConfig?.rememberMeText || 'Remember me'} />\n </div>\n </FormItem>\n )}\n </div>\n <div>\n {authService.isForgotPasswordEnabled() && (\n <Link to=\"forgot-password\" className=\"text-sm transition-colors duration-300\" style={linkStyle}>\n {loginConfig?.forgotPasswordText || 'Forgot password?'}\n </Link>\n )}\n </div>\n </div>\n </FormItem>\n\n <FormItem>\n <Button\n variant=\"primary\"\n {...({ type: 'submit' } as Record<string, string>)}\n className=\"w-full text-base font-medium\"\n disabled={loading}\n fullWidth\n >\n {loading ? (\n <span className=\"inline-flex items-center gap-2\">\n <Loader2 size={16} className=\"animate-spin\" />\n {loginConfig?.submitButtonText || 'Sign in'}\n </span>\n ) : (\n loginConfig?.submitButtonText || 'Sign in'\n )}\n </Button>\n </FormItem>\n </Form>\n );\n };\n\n const renderOTPOption = () => {\n if (!authService.isOTPLoginEnabled()) return null;\n\n const loginConfig = getLoginConfig();\n\n if (showOTPForm) {\n return <OTPForm onSuccess={handleOTPSuccess} onBack={() => setShowOTPForm(false)} />;\n }\n\n return (\n <Button\n variant=\"secondary\"\n fullWidth\n onClick={() => setShowOTPForm(true)}\n className=\"bg-gray-100 border-gray-300\"\n >\n {loginConfig?.otpButtonText || 'Sign in with OTP'}\n </Button>\n );\n };\n\n const renderAuthMethods = () => {\n // Ensure we have auth config loaded\n if (!authConfig) {\n return null;\n }\n\n const allowedUsernames = authService.getAllowedUsernames();\n const hasEmail = allowedUsernames.includes('email');\n const hasMobile = allowedUsernames.includes('mobile');\n const hasProviders = authService.isSSOEnabled() || authService.isOIDCEnabled();\n const isPasswordEnabled = authService.isPasswordLoginEnabled();\n const isOTPEnabled = authService.isOTPLoginEnabled();\n\n // No sign-in method is configured. Returning null renders an empty card the\n // user cannot act on or explain, so say what happened instead — this is a\n // deployment misconfiguration, not a user error.\n if (!isPasswordEnabled && !isOTPEnabled && !hasProviders) {\n logger.error('[Auth] No login method is enabled in the auth config', undefined, {\n enabledMethods: authService.getEnabledLoginMethods(),\n });\n return (\n <Alert\n type=\"warning\"\n showIcon={false}\n message=\"No sign-in method is configured. Please contact your administrator.\"\n />\n );\n }\n\n // When user clicked \"Sign in with OTP\" while password is also enabled,\n // replace the entire view with OTPForm (and a Back link to return).\n if (showOTPForm && isOTPEnabled && isPasswordEnabled) {\n return (\n <div className=\"w-full\">\n <OTPForm onSuccess={handleOTPSuccess} onBack={() => setShowOTPForm(false)} />\n </div>\n );\n }\n\n // If only SSO/OIDC is enabled (no password, no OTP), show SSO/OIDC options only\n if (hasProviders && !isPasswordEnabled && !isOTPEnabled) {\n return (\n <div className=\"w-full\">\n {authService.isSSOEnabled() && (\n <div className=\"mb-4\">\n <div className=\"space-y-2\">\n {(authService.getSSOProviders() as AuthProviderType[]).map((provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"sso\" />\n ))}\n </div>\n </div>\n )}\n\n {authService.isOIDCEnabled() && (\n <div className=\"space-y-2\">\n {(authService.getOIDCProviders() as AuthProviderType[]).map((provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"oidc\" />\n ))}\n </div>\n )}\n </div>\n );\n }\n\n // If only OTP is enabled (no password login), show OTP form directly\n // Also show SSO/OIDC if available\n if (isOTPEnabled && !isPasswordEnabled) {\n const providersConfig = getProvidersConfig();\n return (\n <div className=\"w-full\">\n <OTPForm onSuccess={handleOTPSuccess} />\n {hasProviders && (\n <div className=\"mt-6\">\n <Divider>{providersConfig?.separatorText || 'OR'}</Divider>\n\n {authService.isSSOEnabled() && (\n <div className=\"mb-4\">\n <div className=\"space-y-2\">\n {(authService.getSSOProviders() as AuthProviderType[]).map((provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"sso\" />\n ))}\n </div>\n </div>\n )}\n\n {authService.isOIDCEnabled() && (\n <div className=\"mt-4\">\n <div className=\"space-y-2\">\n {(authService.getOIDCProviders() as AuthProviderType[]).map((provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"oidc\" />\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n }\n\n // Check if we need tabs (only show tabs if both email and mobile are enabled AND password login is enabled)\n const showTabs = hasEmail && hasMobile && isPasswordEnabled;\n\n if (showTabs) {\n // Show tabs when both methods are available\n const loginConfig = getLoginConfig();\n const providersConfig = getProvidersConfig();\n\n return (\n <div className=\"w-full\">\n <Tabs\n className=\"login-tabs\"\n activeKey={activeTab}\n onChange={(key) => {\n setActiveTab(key as 'email' | 'mobile');\n setFormKey((prev) => prev + 1); // Reset form by changing key\n setError(null); // Clear visible error when switching tabs\n }}\n items={[\n {\n key: 'email',\n label: (\n <span className=\"flex items-center gap-1\" style={textStyle}>\n <Mail size={16} />\n {loginConfig?.tabLabels?.email || 'Email'}\n </span>\n ),\n children: (\n <>\n {renderPasswordForm('email')}\n {isOTPEnabled && isPasswordEnabled && !showOTPForm && (\n <div className=\"mt-6\">\n <Divider>{providersConfig?.separatorText || 'OR'}</Divider>\n {renderOTPOption()}\n </div>\n )}\n {showOTPForm && renderOTPOption()}\n {/* SSO and OIDC providers for email tab */}\n {!showOTPForm && hasProviders && (\n <div className=\"mt-6\">\n <Divider>{providersConfig?.separatorText || 'OR'}</Divider>\n\n {authService.isSSOEnabled() && (\n <div className=\"mb-4\">\n <div className=\"space-y-2\">\n {(authService.getSSOProviders() as AuthProviderType[]).map(\n (provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"sso\" />\n ),\n )}\n </div>\n </div>\n )}\n\n {authService.isOIDCEnabled() && (\n <div className=\"mt-4\">\n <div className=\"space-y-2\">\n {(authService.getOIDCProviders() as AuthProviderType[]).map(\n (provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"oidc\" />\n ),\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </>\n ),\n },\n {\n key: 'mobile',\n label: (\n <span className=\"flex items-center gap-1\" style={textStyle}>\n <Smartphone size={16} />\n {loginConfig?.tabLabels?.mobile || 'Mobile'}\n </span>\n ),\n children: (\n <>\n {renderPasswordForm('mobile')}\n {isOTPEnabled && isPasswordEnabled && !showOTPForm && (\n <div className=\"mt-6\">\n <Divider>OR</Divider>\n {renderOTPOption()}\n </div>\n )}\n {showOTPForm && renderOTPOption()}\n {/* SSO and OIDC providers for mobile tab */}\n {!showOTPForm && hasProviders && (\n <div className=\"mt-6\">\n <Divider>OR</Divider>\n\n {authService.isSSOEnabled() && (\n <div className=\"mb-4\">\n <div className=\"space-y-2\">\n {(authService.getSSOProviders() as AuthProviderType[]).map(\n (provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"sso\" />\n ),\n )}\n </div>\n </div>\n )}\n\n {authService.isOIDCEnabled() && (\n <div className=\"mt-4\">\n <div className=\"space-y-2\">\n {(authService.getOIDCProviders() as AuthProviderType[]).map(\n (provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"oidc\" />\n ),\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </>\n ),\n },\n ]}\n />\n </div>\n );\n } else {\n // Show single form without tabs\n const singleMethod = hasEmail ? 'email' : 'mobile';\n return (\n <div className=\"w-full\">\n {renderPasswordForm(singleMethod)}\n {isOTPEnabled && isPasswordEnabled && !showOTPForm && (\n <div className=\"mt-6\">\n <Divider>OR</Divider>\n {renderOTPOption()}\n </div>\n )}\n {showOTPForm && renderOTPOption()}\n\n {/* SSO and OIDC providers */}\n {!showOTPForm && hasProviders && (\n <div className=\"mt-6\">\n <Divider>OR</Divider>\n\n {authService.isSSOEnabled() && (\n <div className=\"mb-4\">\n <div className=\"space-y-2\">\n {(authService.getSSOProviders() as AuthProviderType[]).map((provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"sso\" />\n ))}\n </div>\n </div>\n )}\n\n {authService.isOIDCEnabled() && (\n <div className=\"mt-4\">\n <div className=\"space-y-2\">\n {(authService.getOIDCProviders() as AuthProviderType[]).map((provider: AuthProviderType) => (\n <ProviderButton key={provider.id} provider={provider} type=\"oidc\" />\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n }\n };\n\n // Show loading state while auth config is being loaded\n if (!authConfig) {\n return (\n <div className=\"flex justify-center items-center min-h-loading-min-h\">\n <Spin size=\"large\" />\n </div>\n );\n }\n\n // If user is already logged in, show logout and change password options\n if (isLoggedIn) {\n return (\n <div className=\"w-full\">\n {!showPasswordChange ? (\n <div className=\"space-y-4\">\n <div className=\"text-center mb-4\">\n <h3 className=\"text-lg font-medium\" style={textStyle}>\n Already Logged In\n </h3>\n <p className=\"text-sm mt-2\" style={secondaryTextStyle}>\n You are currently logged in.\n </p>\n </div>\n\n <Button block onClick={() => setShowPasswordChange(true)}>\n Change Password\n </Button>\n\n <Button block danger onClick={handleLogout} loading={loading}>\n Logout\n </Button>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <h4 className=\"text-base font-medium mb-4\">Change Your Password</h4>\n\n <FormItem label=\"New Password\">\n <PasswordInput\n value={newPassword}\n onChange={(e) => setNewPassword(e.target.value)}\n placeholder=\"Enter new password\"\n disabled={loading}\n />\n </FormItem>\n\n <FormItem label=\"Confirm Password\">\n <PasswordInput\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n placeholder=\"Confirm new password\"\n disabled={loading}\n />\n </FormItem>\n\n <div className=\"flex gap-2\">\n <Button type=\"primary\" onClick={handleChangePassword} loading={loading} className=\"flex-1\">\n Change Password\n </Button>\n\n <Button\n onClick={() => {\n setShowPasswordChange(false);\n setNewPassword('');\n setConfirmPassword('');\n }}\n disabled={loading}\n className=\"flex-1\"\n >\n Cancel\n </Button>\n </div>\n </div>\n )}\n </div>\n );\n }\n\n return renderAuthMethods();\n};\n","import { Button, Checkbox, Form, FormItem, Input, PasswordInput, Select, Space, toast } from '@zango-core/components';\nimport { useEffect, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { authService } from '../services/authService';\nimport { passwordMinLengthRule } from '../utils/validators';\nimport { useAuthContext } from './AuthProvider';\n\ninterface LoginFormProps {\n onLogin?: (values: Record<string, unknown>) => Promise<void>;\n showRememberMe?: boolean;\n showForgotPassword?: boolean;\n}\n\nexport const LoginForm = ({ onLogin, showRememberMe = true, showForgotPassword = true }: LoginFormProps) => {\n const [loading, setLoading] = useState(false);\n const [formKey] = useState(0);\n const [selectedUsernameType, setSelectedUsernameType] = useState<string>('email');\n const { authConfig } = useAuthContext();\n\n useEffect(() => {\n if (authConfig) {\n const allowedUsernames = authService.getAllowedUsernames();\n if (allowedUsernames && allowedUsernames.length > 0) {\n setSelectedUsernameType(allowedUsernames[0]);\n }\n }\n }, [authConfig]);\n\n const handleSubmit = async (values: { username: string; password: string; remember?: boolean }) => {\n setLoading(true);\n try {\n if (onLogin) {\n // Map the form values to the expected API format\n const loginData = {\n email: selectedUsernameType === 'email' ? values.username : undefined,\n phone: selectedUsernameType === 'mobile' ? values.username : undefined,\n username: selectedUsernameType === 'username' ? values.username : values.username,\n password: values.password,\n remember_me: values.remember || false,\n };\n await onLogin(loginData);\n }\n } catch (error: unknown) {\n toast.error(error instanceof Error ? error.message : 'Login failed. Please try again.');\n } finally {\n setLoading(false);\n }\n };\n\n const getUsernamePlaceholder = () => {\n switch (selectedUsernameType) {\n case 'email':\n return 'Email address';\n case 'mobile':\n return 'Phone number';\n case 'username':\n return 'Username';\n default:\n return 'Username';\n }\n };\n\n const getUsernameValidationRules = () => {\n const baseRules = [{ required: true, message: `Please input your ${selectedUsernameType}!` }];\n\n switch (selectedUsernameType) {\n case 'email':\n return [...baseRules, { type: 'email' as const, message: 'Please enter a valid email address!' }];\n case 'mobile':\n return [...baseRules, { pattern: /^\\+?[1-9]\\d{1,14}$/, message: 'Please enter a valid phone number!' }];\n case 'username':\n return [...baseRules, { min: 3, message: 'Username must be at least 3 characters long' }];\n default:\n return baseRules;\n }\n };\n\n if (!authConfig) {\n return <div className=\"flex justify-center items-center min-h-loading-min-h\">Loading...</div>;\n }\n\n const allowedUsernames = authService.getAllowedUsernames();\n const showUsernameSelector = allowedUsernames.length > 1;\n const isRememberMeEnabled = authService.isRememberMeEnabled();\n const isForgotPasswordEnabled = authService.isForgotPasswordEnabled();\n\n return (\n <Form\n key={formKey}\n name=\"login\"\n className=\"w-full space-y-4\"\n initialValues={{ remember: false }}\n onFinish={(values) =>\n handleSubmit(values as unknown as { username: string; password: string; remember?: boolean })\n }\n autoComplete=\"off\"\n layout=\"vertical\"\n >\n {showUsernameSelector && (\n <FormItem label=\"Login with\" className=\"mb-4\">\n <Select\n value={selectedUsernameType}\n onChange={(value) => setSelectedUsernameType(String(value))}\n options={allowedUsernames.map((type: string) => ({\n value: type,\n label: type === 'mobile' ? 'Phone' : type.charAt(0).toUpperCase() + type.slice(1),\n }))}\n />\n </FormItem>\n )}\n\n <FormItem name=\"username\" rules={getUsernameValidationRules()}>\n <Input\n className=\"w-full\"\n placeholder={getUsernamePlaceholder()}\n autoComplete={selectedUsernameType === 'email' ? 'email' : 'username'}\n />\n </FormItem>\n\n <FormItem\n name=\"password\"\n rules={[\n { required: true, message: 'Please input your password!' },\n passwordMinLengthRule(authConfig?.password_policy as { min_length?: number } | null | undefined),\n ]}\n >\n <PasswordInput className=\"w-full\" placeholder=\"Password\" autoComplete=\"current-password\" />\n </FormItem>\n\n <FormItem>\n <Space className=\"flex justify-between items-center w-full\">\n {showRememberMe && isRememberMeEnabled && (\n <FormItem name=\"remember\" valuePropName=\"checked\" noStyle>\n <Checkbox label=\"Remember me\" />\n </FormItem>\n )}\n {showForgotPassword && isForgotPasswordEnabled && (\n <Link to=\"forgot-password\" className=\"text-brand-500 text-sm hover:text-brand-600 transition-colors\">\n Forgot password?\n </Link>\n )}\n </Space>\n </FormItem>\n\n <FormItem>\n <Button variant=\"primary\" type=\"submit\" className=\"w-full text-base font-medium\" disabled={loading} fullWidth>\n Log in\n </Button>\n </FormItem>\n </Form>\n );\n};\n","import { Alert, Card, Layout, Spin, toast } from '@zango-core/components';\nimport type React from 'react';\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useIsMobile } from '@/hooks/useMobile';\nimport { logger } from '@/services/logger';\nimport { useAppContext } from '../../framework/contexts/AppContext';\nimport { useAuthConfig } from '../../framework/contexts/AuthConfigContext';\nimport {\n getAuthBackgroundStyle,\n getAuthCardStyle,\n getAuthLogoStyle,\n getAuthSecondaryTextStyle,\n getAuthTextStyle,\n getLogoContainerStyle,\n} from '../../framework/utils/authThemeUtils';\nimport { safeWindowRedirect } from '../../framework/utils/safeRedirect';\nimport { AuthMobileShell } from '../components/AuthMobileShell';\nimport { SSOButtons } from '../components/composable';\nimport { DynamicLoginForm } from '../components/DynamicLoginForm';\nimport { LoginForm } from '../components/LoginForm';\nimport { LoginContext } from '../contexts/LoginContext';\nimport { authService } from '../services/authService';\nimport type { LoginPageProps } from '../types';\nimport { SAMLCallbackPage } from './SAMLCallbackPage';\n\ninterface ExtendedLoginPageProps extends LoginPageProps {\n useDynamicConfig?: boolean;\n staticConfig?: Record<string, unknown> | null;\n}\n\nexport const LoginPage: React.FC<ExtendedLoginPageProps> = ({\n onLogin,\n logo,\n title,\n subtitle,\n apiConfig: _apiConfig = {},\n useDynamicConfig = true,\n staticConfig = null,\n}) => {\n const [searchParams] = useSearchParams();\n const [loginConfig, setLoginConfig] = useState<Record<string, unknown> | null>(null);\n const [loading, setLoading] = useState<boolean>(useDynamicConfig);\n const [error, setError] = useState<string | null>(null);\n const samlErrorShownRef = useRef(false);\n const { appLogo, appName } = useAppContext();\n const isMobile = useIsMobile();\n\n // Check for SAML callback parameters\n const token = searchParams.get('token');\n const requestId = searchParams.get('request_id');\n const isSAMLCallback = !!(token && requestId);\n\n // Handle SAML error from sessionStorage - show toast EXACTLY once\n useLayoutEffect(() => {\n // Check ref first\n if (samlErrorShownRef.current) {\n return; // Already shown, don't check storage\n }\n\n // Read and IMMEDIATELY remove in atomic operation\n const samlError = sessionStorage.getItem('saml_error');\n\n if (samlError) {\n // Set ref FIRST\n samlErrorShownRef.current = true;\n\n // Remove from storage\n sessionStorage.removeItem('saml_error');\n\n // Then show toast\n try {\n const errorData = JSON.parse(samlError);\n toast.error(errorData.message, {\n duration: 5000,\n });\n } catch (e) {\n // If parsing fails, silently ignore (already removed from storage)\n logger.error('Failed to parse SAML error', e);\n }\n }\n }, []); // Empty deps - only run once on mount\n\n // Get authConfig for styling and custom components\n const { authConfig, getCustomComponents } = useAuthConfig();\n const customComponents = getCustomComponents();\n const cardStyle = getAuthCardStyle(authConfig);\n const backgroundStyle = getAuthBackgroundStyle(authConfig);\n const textStyle = getAuthTextStyle(authConfig);\n const secondaryTextStyle = getAuthSecondaryTextStyle(authConfig);\n const logoContainerStyle = getLogoContainerStyle(authConfig);\n const logoStyle = getAuthLogoStyle(authConfig);\n\n // Check for custom page/card components\n const CustomLoginPage = customComponents?.LoginPage;\n const CustomLoginCard = customComponents?.LoginCard;\n\n const fetchLoginMethods = useCallback(async () => {\n try {\n const config = await authService.getAuthConfig();\n setLoginConfig(config);\n setError(null);\n } catch (err) {\n logger.error('Failed to fetch login methods', err);\n\n // Use default configuration instead of showing error\n // This allows the login form to still be usable even if config fetch fails\n const defaultConfig = {\n login_methods: {\n password: {\n enabled: true,\n allowed_usernames: ['email'],\n },\n otp: { enabled: false },\n sso: { enabled: false },\n oidc: { enabled: false },\n },\n password_policy: {\n min_length: 8,\n reset: {\n enabled: true,\n },\n },\n session_policy: {\n remember_me_enabled: true,\n remember_me_duration_days: 30,\n },\n };\n\n setLoginConfig(defaultConfig);\n setError(null); // Don't show error, use defaults\n logger.warn('Using default auth configuration due to config fetch failure');\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n if (useDynamicConfig && !staticConfig) {\n fetchLoginMethods();\n } else if (staticConfig) {\n setLoginConfig(staticConfig);\n setLoading(false);\n }\n }, [useDynamicConfig, staticConfig, fetchLoginMethods]);\n\n // If SAML callback parameters are present, handle SAML flow\n if (isSAMLCallback) {\n return (\n <SAMLCallbackPage\n logo={logo}\n title={title || 'Processing Authentication'}\n subtitle={subtitle || 'Please wait while we complete your login'}\n onAuthComplete={(result: { redirect_url?: string }) => {\n // Default redirect behavior - you can customize this\n const redirectUrl = result?.redirect_url || '/app';\n // Clean token and request_id from URL before redirecting\n try {\n const url = new URL(redirectUrl, window.location.origin);\n url.searchParams.delete('token');\n url.searchParams.delete('request_id');\n const cleanUrl = url.pathname + (url.search ? url.search : '');\n safeWindowRedirect(cleanUrl);\n } catch (_e) {\n // Fallback if URL parsing fails\n safeWindowRedirect(redirectUrl);\n }\n }}\n roleSelectionTitle=\"Select Your Role\"\n roleSelectionSubtitle=\"Choose a role to continue\"\n twoFactorTitle=\"Two-Factor Authentication\"\n twoFactorSubtitle=\"For your security, please verify your identity\"\n passwordResetTitle=\"Password Update Required\"\n passwordResetSubtitle=\"Please create a new password to continue\"\n />\n );\n }\n\n const renderLoginForm = () => {\n if (loading) {\n return (\n <div className=\"flex justify-center items-center min-h-loading-min-h\">\n <Spin size=\"large\" tip=\"Loading login methods...\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <Alert\n message=\"Error\"\n description={error}\n type=\"error\"\n showIcon\n action={\n <button type=\"button\" onClick={fetchLoginMethods}>\n Retry\n </button>\n }\n />\n );\n }\n\n // Use DynamicLoginForm if config is available, otherwise fall back to simple LoginForm\n if (loginConfig && useDynamicConfig) {\n return <DynamicLoginForm onLogin={onLogin as unknown as (data: import('../../types').LoginCredentials | import('../utils/authFlowHandler').AuthResponse) => Promise<void>} />;\n }\n\n // Fallback to simple login form\n return <LoginForm onLogin={onLogin as unknown as (values: Record<string, unknown>) => Promise<void>} />;\n };\n\n // Priority: CustomLoginPage > CustomLoginCard > Default page layout\n // Note: SAML callback handling (token/requestId check) is at the top of the component,\n // so if we reach here, it's a normal login page render (no SAML callback in progress)\n\n // Full page replacement\n // Skip custom page if SAML callback params are present - let SAMLCallbackPage handle it\n if (CustomLoginPage && !token && !requestId) {\n return (\n <LoginContext.Provider value={{ onLogin: (onLogin as unknown as (result: unknown) => void) || (() => {}) }}>\n <CustomLoginPage />\n </LoginContext.Provider>\n );\n }\n\n // Card-only replacement (keeps page wrapper, background, etc.)\n if (CustomLoginCard) {\n return (\n <LoginContext.Provider value={{ onLogin: (onLogin as unknown as (result: unknown) => void) || (() => {}) }}>\n <Layout className=\"min-h-screen\" style={backgroundStyle}>\n <Layout.Content className=\"flex justify-center items-center min-h-screen p-5\">\n <Card className=\"w-full max-w-md\" bordered={false} style={cardStyle}>\n <CustomLoginCard />\n </Card>\n </Layout.Content>\n </Layout>\n </LoginContext.Provider>\n );\n }\n\n // E2E test view: render only SSOButtons with layout from query (for sso-buttons specs)\n // Gated to non-production — stripped from prod builds by Vite\n if (import.meta.env.MODE !== 'production') {\n const view = searchParams.get('view');\n const layoutParam = searchParams.get('layout');\n const ssoLayout = layoutParam === 'grid' || layoutParam === 'row' ? layoutParam : 'column';\n if (view === 'sso-buttons' && !token && !requestId) {\n return (\n <Layout className=\"min-h-screen\" style={backgroundStyle}>\n <Layout.Content className=\"flex justify-center items-center min-h-screen p-5\">\n <Card className=\"w-full max-w-md\" bordered={false} style={cardStyle}>\n <h2 className=\"text-xl font-semibold mb-4\" style={textStyle}>\n SSO Buttons\n </h2>\n <SSOButtons layout={ssoLayout} />\n </Card>\n </Layout.Content>\n </Layout>\n );\n }\n }\n\n if (isMobile) {\n return (\n <AuthMobileShell appName={appName} appLogo={typeof logo === 'string' ? logo : appLogo}>\n <div className=\"text-center mb-[22px]\">\n {(() => {\n const heading = title || 'Welcome Back';\n const parts = heading.trim().split(/\\s+/);\n const last = parts.pop();\n const lead = parts.join(' ');\n return (\n <h1 className=\"mb-2\" style={textStyle}>\n {lead ? `${lead} ` : ''}\n <em className=\"accent\">{last}.</em>\n </h1>\n );\n })()}\n {subtitle && (\n <p className=\"text-sm\" style={secondaryTextStyle}>\n {subtitle}\n </p>\n )}\n </div>\n {renderLoginForm()}\n </AuthMobileShell>\n );\n }\n\n // Default page layout\n return (\n <Layout className=\"min-h-screen\" style={backgroundStyle}>\n <Layout.Content className=\"flex justify-center items-center min-h-screen p-5\">\n <Card className=\"w-full max-w-md\" bordered={false} style={cardStyle}>\n {logo && (\n <div className={logoContainerStyle.className} style={logoContainerStyle.style}>\n {typeof logo === 'string' ? (\n <img\n src={logo}\n alt={authConfig?.logo?.alt || 'Logo'}\n className=\"max-w-logo-max-w h-auto\"\n style={logoStyle}\n />\n ) : (\n logo\n )}\n </div>\n )}\n <div className=\"text-center mb-[18px]\">\n <h1 className=\"text-3xl font-semibold mb-2\" style={textStyle}>\n {title || 'Welcome Back'}\n </h1>\n {subtitle && (\n <p className=\"text-base\" style={secondaryTextStyle}>\n {subtitle}\n </p>\n )}\n </div>\n {renderLoginForm()}\n </Card>\n </Layout.Content>\n </Layout>\n );\n};\n","import { Layout } from '@zango-core/components';\nimport React, { useCallback, useState } from 'react';\nimport { useIsMobile } from '@/hooks/useMobile';\nimport { logger } from '@/services/logger';\nimport { useAppContext } from '../../framework/contexts/AppContext';\nimport { useAuthConfig } from '../../framework/contexts/AuthConfigContext';\nimport { getAuthBackgroundStyle } from '../../framework/utils/authThemeUtils';\nimport { AuthMobileShell } from '../components/AuthMobileShell';\nimport { useAuthContext } from '../components/AuthProvider';\nimport { RoleSelection } from '../components/RoleSelection';\nimport { authService } from '../services/authService';\nimport { LoginPage } from './LoginPage';\n\nconst { Content } = Layout;\n\nexport const LoginPageWithRoleSelection = ({\n logo,\n title,\n subtitle,\n apiConfig,\n useDynamicConfig = true,\n staticConfig = null,\n onLoginSuccess,\n roleSelectionTitle,\n roleSelectionSubtitle,\n initialAuthResult = null,\n}: {\n logo?: React.ReactNode;\n title?: string;\n subtitle?: string;\n apiConfig?: Record<string, unknown>;\n useDynamicConfig?: boolean;\n staticConfig?: Record<string, unknown> | null;\n onLoginSuccess?: (result: unknown) => void;\n roleSelectionTitle?: string;\n roleSelectionSubtitle?: string;\n initialAuthResult?: unknown;\n}) => {\n const { pendingAuth, availableRoles, login, processAuthResult } = useAuthContext();\n const [, setLoginError] = useState<string | null>(null);\n const isMobile = useIsMobile();\n const { appName, appLogo } = useAppContext();\n const { getCustomComponents } = useAuthConfig();\n const customComponentKey = getCustomComponents()?.LoginPage\n ? 'custom'\n : getCustomComponents()?.LoginCard\n ? 'card'\n : 'default';\n\n const handleLogin = useCallback(\n async (credentials: Record<string, unknown>) => {\n setLoginError(null);\n try {\n // Check if the argument is already a login result (from composable components)\n // Composable components perform the login themselves and pass the result\n if (credentials && (credentials.status || credentials.data || credentials.next_step || credentials.response)) {\n const result = processAuthResult(credentials);\n if (result?.requiresRoleSelection) {\n return;\n }\n // Single role — auto-select via API\n if (result?.autoSelectedRole) {\n const roleResult = await authService.selectRole((result.autoSelectedRole as { id: string }).id);\n\n if (onLoginSuccess) {\n onLoginSuccess(roleResult);\n }\n return;\n }\n\n if (onLoginSuccess) {\n onLoginSuccess(credentials);\n }\n return;\n }\n\n const result = await login(credentials as unknown as import('../../types').LoginCredentials);\n\n // Store credentials for later use\n const loginUser = {\n email: credentials.email,\n username: credentials.username,\n phone: credentials.phone,\n // Use whichever credential was provided\n display: credentials.email || credentials.username || credentials.phone,\n };\n\n if (result.requiresRoleSelection) {\n // Stay on this page, role selection will be shown\n return;\n }\n\n // Login successful and no role selection needed\n if (onLoginSuccess) {\n onLoginSuccess({ ...result, loginUser });\n }\n } catch (error: unknown) {\n const errorMsg = error instanceof Error ? error.message : 'Login failed';\n setLoginError(errorMsg);\n throw error; // Re-throw to let the form handle it\n }\n },\n [login, processAuthResult, onLoginSuccess],\n );\n\n // Process initialAuthResult if provided (from custom login pages)\n React.useEffect(() => {\n if (initialAuthResult) {\n handleLogin(initialAuthResult as Record<string, unknown>);\n }\n }, [initialAuthResult, handleLogin]);\n\n const handleRoleSelect = async (role: { id: string }) => {\n try {\n const result = await authService.selectRole(role.id);\n if (onLoginSuccess) {\n onLoginSuccess(result);\n }\n } catch (error) {\n logger.error('Role selection failed', error);\n throw error;\n }\n };\n\n // Show role selection if we have pending authentication\n if (pendingAuth && availableRoles) {\n const backgroundStyle = getAuthBackgroundStyle(apiConfig || staticConfig || {});\n const roleSelectionContent = (\n <RoleSelection\n user={pendingAuth.user as { id?: string; name?: string; username?: string; email?: string } | undefined}\n roles={availableRoles as { id: string; name: string; description?: string; permissions?: string[]; is_default?: boolean }[]}\n onRoleSelect={handleRoleSelect}\n title={roleSelectionTitle}\n subtitle={roleSelectionSubtitle}\n />\n );\n\n if (isMobile) {\n return (\n <AuthMobileShell appName={appName} appLogo={typeof logo === 'string' ? logo : appLogo}>\n {roleSelectionContent}\n </AuthMobileShell>\n );\n }\n\n return (\n <Layout className=\"min-h-screen\" style={backgroundStyle}>\n <Content className=\"flex justify-center items-center min-h-screen p-5\">{roleSelectionContent}</Content>\n </Layout>\n );\n }\n\n // Show login page\n return (\n <LoginPage\n key={customComponentKey}\n onLogin={handleLogin as unknown as (credentials: import('../types').LoginCredentials) => Promise<import('../types').AuthResult>}\n logo={logo}\n title={title}\n subtitle={subtitle}\n apiConfig={apiConfig}\n useDynamicConfig={useDynamicConfig}\n staticConfig={staticConfig}\n />\n );\n};\n"],"names":["DynamicLoginForm","onLogin","showRememberMe","loading","setLoading","useState","error","setError","setActiveMethod","activeTab","setActiveTab","showOTPForm","setShowOTPForm","formKey","setFormKey","isLoggedIn","setIsLoggedIn","showPasswordChange","setShowPasswordChange","newPassword","setNewPassword","confirmPassword","setConfirmPassword","authConfig","useAuthContext","getLoginConfig","getMessagesConfig","getProvidersConfig","configContext","useAuthConfig","effectiveAuthConfig","textStyle","getAuthTextStyle","secondaryTextStyle","getAuthSecondaryTextStyle","linkStyle","getAuthLinkStyle","checkAuthentication","useCallback","authService","useEffect","defaultMethod","allowedUsernames","hasEmail","hasMobile","isAuthenticated","jsx","Spin","getUsernameRules","type","messagesConfig","handleMobileKeyDown","e","handlePasswordLogin","values","method","loginData","errorMessage","handleOTPSuccess","result","handleLogout","toast","handleChangePassword","renderPasswordForm","loginConfig","jsxs","Form","Alert","FormItem","Input","passwordMinLengthRule","PasswordInput","Checkbox","Link","Button","Loader2","renderOTPOption","OTPForm","renderAuthMethods","hasProviders","isPasswordEnabled","isOTPEnabled","logger","provider","ProviderButton","providersConfig","Divider","Tabs","key","prev","Mail","Fragment","Smartphone","LoginForm","showForgotPassword","selectedUsernameType","setSelectedUsernameType","handleSubmit","getUsernamePlaceholder","getUsernameValidationRules","baseRules","showUsernameSelector","isRememberMeEnabled","isForgotPasswordEnabled","Select","value","Space","LoginPage","logo","title","subtitle","_apiConfig","useDynamicConfig","staticConfig","searchParams","useSearchParams","setLoginConfig","samlErrorShownRef","useRef","appLogo","appName","useAppContext","isMobile","useIsMobile","token","requestId","isSAMLCallback","useLayoutEffect","samlError","errorData","getCustomComponents","customComponents","cardStyle","getAuthCardStyle","backgroundStyle","getAuthBackgroundStyle","logoContainerStyle","getLogoContainerStyle","logoStyle","getAuthLogoStyle","CustomLoginPage","CustomLoginCard","fetchLoginMethods","config","err","SAMLCallbackPage","redirectUrl","url","cleanUrl","safeWindowRedirect","renderLoginForm","LoginContext","Layout","Card","AuthMobileShell","parts","last","lead","Content","LoginPageWithRoleSelection","apiConfig","onLoginSuccess","roleSelectionTitle","roleSelectionSubtitle","initialAuthResult","pendingAuth","availableRoles","login","processAuthResult","setLoginError","customComponentKey","handleLogin","credentials","roleResult","loginUser","errorMsg","React","handleRoleSelect","role","roleSelectionContent","RoleSelection"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import r from "react";
|
|
2
|
+
import { N as u, L as d, T as p, C as l, a as c } from "./index.framework-B8SMzgN1.js";
|
|
3
|
+
const h = {
|
|
4
|
+
crud: {
|
|
5
|
+
component: l,
|
|
6
|
+
includeBasePath: !0,
|
|
7
|
+
// standalone:true,
|
|
8
|
+
propsBuilder: ({ matchedRoutePath: e }) => ({})
|
|
9
|
+
},
|
|
10
|
+
training: {
|
|
11
|
+
component: p,
|
|
12
|
+
includeBasePath: !0,
|
|
13
|
+
propsBuilder: ({ matchedRoutePath: e }) => ({})
|
|
14
|
+
},
|
|
15
|
+
login: {
|
|
16
|
+
component: d,
|
|
17
|
+
includeBasePath: !0,
|
|
18
|
+
// Login needs basePath for sub-routes
|
|
19
|
+
standalone: !0,
|
|
20
|
+
// Render without layout (no sidebar/topbar)
|
|
21
|
+
propsBuilder: ({ matchedRoutePath: e }) => ({})
|
|
22
|
+
},
|
|
23
|
+
custom: {
|
|
24
|
+
component: null,
|
|
25
|
+
includeBasePath: !1,
|
|
26
|
+
// Explicitly disable basePath for custom pages
|
|
27
|
+
handler: ({ customPages: e, customPagePath: t, location: a, matchedRoute: s }) => {
|
|
28
|
+
const n = s || t && { path: null, component: t }, o = e[t];
|
|
29
|
+
return o ? r.createElement(o, { routeConfig: n, location: a }) : r.createElement(c, { componentName: t, routeConfig: n, location: a });
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
404: {
|
|
33
|
+
component: u,
|
|
34
|
+
standalone: !0,
|
|
35
|
+
includeBasePath: !1,
|
|
36
|
+
// Explicitly disable basePath for 404
|
|
37
|
+
propsBuilder: () => ({})
|
|
38
|
+
},
|
|
39
|
+
// Default configuration for unknown page types
|
|
40
|
+
default: {
|
|
41
|
+
component: u,
|
|
42
|
+
includeBasePath: !1,
|
|
43
|
+
// Explicitly disable for unknown types
|
|
44
|
+
standalone: !0,
|
|
45
|
+
propsBuilder: ({ pageType: e }) => ({
|
|
46
|
+
message: `Unknown page type: ${e}`
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
export {
|
|
51
|
+
h as pageTypeRegistry
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=PageTypeRegistry-5269IpiS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageTypeRegistry-5269IpiS.js","sources":["../src/framework/routing/PageTypeRegistry.ts"],"sourcesContent":["import React from 'react';\nimport { CustomPageLoader } from '../components/CustomPageLoader';\nimport { CrudPage } from '../pages/CrudPage';\nimport { LoginPage } from '../pages/LoginPage';\nimport { NotFoundPage } from '../pages/NotFoundPage';\nimport { TrainingPage } from '../pages/TrainingPage';\n\ninterface PageComponentProps {\n basePath?: string;\n matchedRoutePath?: string;\n pageType?: string;\n apiConfig?: {\n apiUrl?: string;\n headers?: Record<string, string>;\n };\n [key: string]: unknown;\n}\n\ninterface CustomPageHandlerParams {\n customPages: Record<string, React.ComponentType<Record<string, unknown>>>;\n customPagePath: string;\n location: Location;\n matchedRoute?: { path: string | null; component?: string; [key: string]: unknown } | null;\n [key: string]: unknown;\n}\n\nexport interface PageTypeConfig {\n component?: React.ComponentType<PageComponentProps> | null;\n includeBasePath?: boolean;\n standalone?: boolean;\n propsBuilder?: (params: PageComponentProps) => Record<string, unknown>;\n handler?: (params: CustomPageHandlerParams) => React.ReactElement;\n}\n\ninterface PageTypeRegistry {\n [key: string]: PageTypeConfig;\n}\n\n/**\n * Page Type Registry - Centralized configuration for all page types\n *\n * Each page type can have:\n * - component: The React component to render\n * - includeBasePath: Whether to pass basePath prop (defaults to true)\n * - propsBuilder: Function to build additional props\n * - handler: Custom rendering function (overrides component)\n */\nexport const pageTypeRegistry: PageTypeRegistry = {\n crud: {\n component: CrudPage,\n includeBasePath: true,\n // standalone:true,\n propsBuilder: ({ matchedRoutePath: _matchedRoutePath }) => ({}),\n },\n\n training: {\n component: TrainingPage,\n includeBasePath: true,\n propsBuilder: ({ matchedRoutePath: _matchedRoutePath }) => ({}),\n },\n\n login: {\n component: LoginPage,\n includeBasePath: true, // Login needs basePath for sub-routes\n standalone: true, // Render without layout (no sidebar/topbar)\n propsBuilder: ({ matchedRoutePath: _matchedRoutePath }) => ({}),\n },\n\n custom: {\n component: null,\n includeBasePath: false, // Explicitly disable basePath for custom pages\n handler: ({ customPages, customPagePath, location, matchedRoute }: CustomPageHandlerParams) => {\n const routeConfig = matchedRoute || (customPagePath && { path: null, component: customPagePath });\n const CustomComponent = customPages[customPagePath];\n if (CustomComponent) {\n return React.createElement(CustomComponent, { routeConfig, location });\n }\n // Fallback to CustomPageLoader with component name from route config\n return React.createElement(CustomPageLoader, { componentName: customPagePath, routeConfig, location } as Record<\n string,\n unknown\n >);\n },\n },\n\n 404: {\n component: NotFoundPage as React.ComponentType<PageComponentProps>,\n standalone: true,\n includeBasePath: false, // Explicitly disable basePath for 404\n propsBuilder: () => ({}),\n },\n\n // Default configuration for unknown page types\n default: {\n component: NotFoundPage as React.ComponentType<PageComponentProps>,\n includeBasePath: false, // Explicitly disable for unknown types\n standalone: true,\n propsBuilder: ({ pageType }) => ({\n message: `Unknown page type: ${pageType}`,\n }),\n },\n};\n"],"names":["pageTypeRegistry","CrudPage","_matchedRoutePath","TrainingPage","LoginPage","customPages","customPagePath","location","matchedRoute","routeConfig","CustomComponent","React","CustomPageLoader","NotFoundPage","pageType"],"mappings":";;AA+CO,MAAMA,IAAqC;AAAA,EAChD,MAAM;AAAA,IACJ,WAAWC;AAAA,IACX,iBAAiB;AAAA;AAAA,IAEjB,cAAc,CAAC,EAAE,kBAAkBC,EAAA,OAAyB,CAAA;AAAA,EAAC;AAAA,EAG/D,UAAU;AAAA,IACR,WAAWC;AAAA,IACX,iBAAiB;AAAA,IACjB,cAAc,CAAC,EAAE,kBAAkBD,EAAA,OAAyB,CAAA;AAAA,EAAC;AAAA,EAG/D,OAAO;AAAA,IACL,WAAWE;AAAA,IACX,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA,IACZ,cAAc,CAAC,EAAE,kBAAkBF,EAAA,OAAyB,CAAA;AAAA,EAAC;AAAA,EAG/D,QAAQ;AAAA,IACN,WAAW;AAAA,IACX,iBAAiB;AAAA;AAAA,IACjB,SAAS,CAAC,EAAE,aAAAG,GAAa,gBAAAC,GAAgB,UAAAC,GAAU,cAAAC,QAA4C;AAC7F,YAAMC,IAAcD,KAAiBF,KAAkB,EAAE,MAAM,MAAM,WAAWA,EAAA,GAC1EI,IAAkBL,EAAYC,CAAc;AAClD,aAAII,IACKC,EAAM,cAAcD,GAAiB,EAAE,aAAAD,GAAa,UAAAF,GAAU,IAGhEI,EAAM,cAAcC,GAAkB,EAAE,eAAeN,GAAgB,aAAAG,GAAa,UAAAF,GAG1F;AAAA,IACH;AAAA,EAAA;AAAA,EAGF,KAAK;AAAA,IACH,WAAWM;AAAA,IACX,YAAY;AAAA,IACZ,iBAAiB;AAAA;AAAA,IACjB,cAAc,OAAO,CAAA;AAAA,EAAC;AAAA;AAAA,EAIxB,SAAS;AAAA,IACP,WAAWA;AAAA,IACX,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc,CAAC,EAAE,UAAAC,SAAgB;AAAA,MAC/B,SAAS,sBAAsBA,CAAQ;AAAA,IAAA;AAAA,EACzC;AAEJ;"}
|