@payez/next-mvp 4.0.1 → 4.0.2
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/api/auth-handler.d.ts +66 -0
- package/dist/api/auth-handler.js +397 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +19 -0
- package/dist/api-handlers/account/change-password.d.ts +9 -0
- package/dist/api-handlers/account/change-password.js +110 -0
- package/dist/api-handlers/account/masked-info.d.ts +2 -0
- package/dist/api-handlers/account/masked-info.js +41 -0
- package/dist/api-handlers/account/profile.d.ts +3 -0
- package/dist/api-handlers/account/profile.js +63 -0
- package/dist/api-handlers/account/recovery/initiate.d.ts +2 -0
- package/dist/api-handlers/account/recovery/initiate.js +26 -0
- package/dist/api-handlers/account/recovery/send-code.d.ts +2 -0
- package/dist/api-handlers/account/recovery/send-code.js +28 -0
- package/dist/api-handlers/account/recovery/verify-code.d.ts +2 -0
- package/dist/api-handlers/account/recovery/verify-code.js +28 -0
- package/dist/api-handlers/account/reset-password.d.ts +2 -0
- package/dist/api-handlers/account/reset-password.js +26 -0
- package/dist/api-handlers/account/send-code.d.ts +24 -0
- package/dist/api-handlers/account/send-code.js +60 -0
- package/dist/api-handlers/account/update-phone.d.ts +27 -0
- package/dist/api-handlers/account/update-phone.js +64 -0
- package/dist/api-handlers/account/validate-password.d.ts +17 -0
- package/dist/api-handlers/account/validate-password.js +81 -0
- package/dist/api-handlers/account/verify-email.d.ts +26 -0
- package/dist/api-handlers/account/verify-email.js +106 -0
- package/dist/api-handlers/account/verify-sms.d.ts +26 -0
- package/dist/api-handlers/account/verify-sms.js +106 -0
- package/dist/api-handlers/admin/analytics.d.ts +19 -0
- package/dist/api-handlers/admin/analytics.js +378 -0
- package/dist/api-handlers/admin/audit.d.ts +19 -0
- package/dist/api-handlers/admin/audit.js +213 -0
- package/dist/api-handlers/admin/index.d.ts +21 -0
- package/dist/api-handlers/admin/index.js +42 -0
- package/dist/api-handlers/admin/redis-sessions.d.ts +35 -0
- package/dist/api-handlers/admin/redis-sessions.js +203 -0
- package/dist/api-handlers/admin/sessions.d.ts +20 -0
- package/dist/api-handlers/admin/sessions.js +283 -0
- package/dist/api-handlers/admin/site-logs.d.ts +45 -0
- package/dist/api-handlers/admin/site-logs.js +317 -0
- package/dist/api-handlers/admin/stats.d.ts +20 -0
- package/dist/api-handlers/admin/stats.js +239 -0
- package/dist/api-handlers/admin/users.d.ts +19 -0
- package/dist/api-handlers/admin/users.js +221 -0
- package/dist/api-handlers/admin/vibe-data.d.ts +79 -0
- package/dist/api-handlers/admin/vibe-data.js +267 -0
- package/dist/api-handlers/anon/preferences.d.ts +37 -0
- package/dist/api-handlers/anon/preferences.js +96 -0
- package/dist/api-handlers/auth/jwks.d.ts +2 -0
- package/dist/api-handlers/auth/jwks.js +24 -0
- package/dist/api-handlers/auth/login.d.ts +42 -0
- package/dist/api-handlers/auth/login.js +178 -0
- package/dist/api-handlers/auth/refresh.d.ts +74 -0
- package/dist/api-handlers/auth/refresh.js +633 -0
- package/dist/api-handlers/auth/signout.d.ts +37 -0
- package/dist/api-handlers/auth/signout.js +186 -0
- package/dist/api-handlers/auth/status.d.ts +8 -0
- package/dist/api-handlers/auth/status.js +23 -0
- package/dist/api-handlers/auth/update-session.d.ts +37 -0
- package/dist/api-handlers/auth/update-session.js +93 -0
- package/dist/api-handlers/auth/validate.d.ts +6 -0
- package/dist/api-handlers/auth/validate.js +43 -0
- package/dist/api-handlers/auth/verify-code.d.ts +43 -0
- package/dist/api-handlers/auth/verify-code.js +90 -0
- package/dist/api-handlers/session/refresh-viability.d.ts +14 -0
- package/dist/api-handlers/session/refresh-viability.js +39 -0
- package/dist/api-handlers/session/viability.d.ts +13 -0
- package/dist/api-handlers/session/viability.js +114 -0
- package/dist/api-handlers/test/force-expire.d.ts +23 -0
- package/dist/api-handlers/test/force-expire.js +59 -0
- package/dist/auth/auth-decision.d.ts +39 -0
- package/dist/auth/auth-decision.js +182 -0
- package/dist/auth/better-auth.d.ts +79 -0
- package/dist/auth/better-auth.js +119 -0
- package/dist/auth/route-config.d.ts +66 -0
- package/dist/auth/route-config.js +190 -0
- package/dist/auth/types/auth-types.d.ts +417 -0
- package/dist/auth/types/auth-types.js +53 -0
- package/dist/auth/types/index.d.ts +6 -0
- package/dist/auth/types/index.js +22 -0
- package/dist/auth/unauthenticated-routes.d.ts +1 -0
- package/dist/auth/unauthenticated-routes.js +19 -0
- package/dist/auth/utils/idp-client.d.ts +94 -0
- package/dist/auth/utils/idp-client.js +384 -0
- package/dist/auth/utils/index.d.ts +5 -0
- package/dist/auth/utils/index.js +21 -0
- package/dist/auth/utils/token-utils.d.ts +83 -0
- package/dist/auth/utils/token-utils.js +218 -0
- package/dist/client/AuthContext.d.ts +19 -0
- package/dist/client/AuthContext.js +115 -0
- package/dist/client/better-auth-client.d.ts +1020 -0
- package/dist/client/better-auth-client.js +68 -0
- package/dist/client/fetch-with-auth.d.ts +11 -0
- package/dist/client/fetch-with-auth.js +44 -0
- package/dist/client/fetchWithSession.d.ts +3 -0
- package/dist/client/fetchWithSession.js +24 -0
- package/dist/client/index.d.ts +9 -0
- package/dist/client/index.js +20 -0
- package/dist/client/useAnonSession.d.ts +36 -0
- package/dist/client/useAnonSession.js +99 -0
- package/dist/components/SessionSync.d.ts +13 -0
- package/dist/components/SessionSync.js +121 -0
- package/dist/components/SignalRHealthCheck.d.ts +10 -0
- package/dist/components/SignalRHealthCheck.js +97 -0
- package/dist/components/account/MobileNavDrawer.d.ts +32 -0
- package/dist/components/account/MobileNavDrawer.js +81 -0
- package/dist/components/account/UserAvatarMenu.d.ts +20 -0
- package/dist/components/account/UserAvatarMenu.js +91 -0
- package/dist/components/account/index.d.ts +9 -0
- package/dist/components/account/index.js +13 -0
- package/dist/components/admin/AlertSettingsTab.d.ts +48 -0
- package/dist/components/admin/AlertSettingsTab.js +351 -0
- package/dist/components/admin/AnalyticsTab.d.ts +22 -0
- package/dist/components/admin/AnalyticsTab.js +167 -0
- package/dist/components/admin/DataBrowserTab.d.ts +19 -0
- package/dist/components/admin/DataBrowserTab.js +252 -0
- package/dist/components/admin/LoggingSettingsTab.d.ts +73 -0
- package/dist/components/admin/LoggingSettingsTab.js +339 -0
- package/dist/components/admin/SessionsTab.d.ts +37 -0
- package/dist/components/admin/SessionsTab.js +165 -0
- package/dist/components/admin/StatsTab.d.ts +53 -0
- package/dist/components/admin/StatsTab.js +161 -0
- package/dist/components/admin/VibeAdminContext.d.ts +32 -0
- package/dist/components/admin/VibeAdminContext.js +38 -0
- package/dist/components/admin/VibeAdminLayout.d.ts +11 -0
- package/dist/components/admin/VibeAdminLayout.js +71 -0
- package/dist/components/admin/index.d.ts +29 -0
- package/dist/components/admin/index.js +44 -0
- package/dist/components/auth/FederatedAuthSection.d.ts +8 -0
- package/dist/components/auth/FederatedAuthSection.js +45 -0
- package/dist/components/auth/ModeAwareLoginPage.d.ts +10 -0
- package/dist/components/auth/ModeAwareLoginPage.js +42 -0
- package/dist/components/auth/ModeAwareSignupPage.d.ts +9 -0
- package/dist/components/auth/ModeAwareSignupPage.js +78 -0
- package/dist/components/auth/TraditionalAuthSection.d.ts +14 -0
- package/dist/components/auth/TraditionalAuthSection.js +20 -0
- package/dist/components/recovery/CompleteStep.d.ts +5 -0
- package/dist/components/recovery/CompleteStep.js +8 -0
- package/dist/components/recovery/InitiateRecoveryStep.d.ts +8 -0
- package/dist/components/recovery/InitiateRecoveryStep.js +20 -0
- package/dist/components/recovery/SelectMethodStep.d.ts +8 -0
- package/dist/components/recovery/SelectMethodStep.js +8 -0
- package/dist/components/recovery/SetPasswordStep.d.ts +6 -0
- package/dist/components/recovery/SetPasswordStep.js +20 -0
- package/dist/components/recovery/VerifyCodeStep.d.ts +10 -0
- package/dist/components/recovery/VerifyCodeStep.js +24 -0
- package/dist/components/reserved/ReservedRecoveryWarning.d.ts +38 -0
- package/dist/components/reserved/ReservedRecoveryWarning.js +92 -0
- package/dist/components/reserved/ReservedStatusBox.d.ts +30 -0
- package/dist/components/reserved/ReservedStatusBox.js +71 -0
- package/dist/components/ui/BetaBadge.d.ts +29 -0
- package/dist/components/ui/BetaBadge.js +38 -0
- package/dist/components/ui/Footer.d.ts +37 -0
- package/dist/components/ui/Footer.js +41 -0
- package/dist/config/env.d.ts +66 -0
- package/dist/config/env.js +57 -0
- package/dist/config/logger.d.ts +57 -0
- package/dist/config/logger.js +73 -0
- package/dist/config/logging-config.d.ts +30 -0
- package/dist/config/logging-config.js +122 -0
- package/dist/config/unauthenticated-routes.d.ts +17 -0
- package/dist/config/unauthenticated-routes.js +24 -0
- package/dist/config/vibe-log-transport.d.ts +81 -0
- package/dist/config/vibe-log-transport.js +212 -0
- package/dist/edge/internal-api-url.d.ts +53 -0
- package/dist/edge/internal-api-url.js +63 -0
- package/dist/edge/middleware.d.ts +14 -0
- package/dist/edge/middleware.js +32 -0
- package/dist/hooks/useAuth.d.ts +23 -0
- package/dist/hooks/useAuth.js +83 -0
- package/dist/hooks/useAuthSettings.d.ts +59 -0
- package/dist/hooks/useAuthSettings.js +93 -0
- package/dist/hooks/useAvailableProviders.d.ts +43 -0
- package/dist/hooks/useAvailableProviders.js +112 -0
- package/dist/hooks/usePasswordValidation.d.ts +27 -0
- package/dist/hooks/usePasswordValidation.js +102 -0
- package/dist/hooks/useProfile.d.ts +15 -0
- package/dist/hooks/useProfile.js +59 -0
- package/dist/hooks/usePublicAuthSettings.d.ts +56 -0
- package/dist/hooks/usePublicAuthSettings.js +131 -0
- package/dist/hooks/useSessionExpiration.d.ts +56 -0
- package/dist/hooks/useSessionExpiration.js +72 -0
- package/dist/hooks/useViabilitySession.d.ts +75 -0
- package/dist/hooks/useViabilitySession.js +269 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +53 -0
- package/dist/lib/anon-session.d.ts +74 -0
- package/dist/lib/anon-session.js +169 -0
- package/dist/lib/api-handler.d.ts +123 -0
- package/dist/lib/api-handler.js +478 -0
- package/dist/lib/app-slug.d.ts +95 -0
- package/dist/lib/app-slug.js +172 -0
- package/dist/lib/demo-mode.d.ts +6 -0
- package/dist/lib/demo-mode.js +16 -0
- package/dist/lib/geolocation.d.ts +64 -0
- package/dist/lib/geolocation.js +235 -0
- package/dist/lib/idp-client-config.d.ts +75 -0
- package/dist/lib/idp-client-config.js +425 -0
- package/dist/lib/idp-fetch.d.ts +14 -0
- package/dist/lib/idp-fetch.js +91 -0
- package/dist/lib/internal-api.d.ts +87 -0
- package/dist/lib/internal-api.js +122 -0
- package/dist/lib/jwt-decode-client.d.ts +10 -0
- package/dist/lib/jwt-decode-client.js +46 -0
- package/dist/lib/jwt-decode.d.ts +48 -0
- package/dist/lib/jwt-decode.js +57 -0
- package/dist/lib/rate-limit-service.d.ts +23 -0
- package/dist/lib/rate-limit-service.js +6 -0
- package/dist/lib/redis.d.ts +5 -0
- package/dist/lib/redis.js +28 -0
- package/dist/lib/refresh-token-validator.d.ts +13 -0
- package/dist/lib/refresh-token-validator.js +117 -0
- package/dist/lib/roles.d.ts +145 -0
- package/dist/lib/roles.js +168 -0
- package/dist/lib/secret-validation.d.ts +4 -0
- package/dist/lib/secret-validation.js +14 -0
- package/dist/lib/session-store.d.ts +170 -0
- package/dist/lib/session-store.js +545 -0
- package/dist/lib/session.d.ts +21 -0
- package/dist/lib/session.js +26 -0
- package/dist/lib/site-logger.d.ts +214 -0
- package/dist/lib/site-logger.js +210 -0
- package/dist/lib/standardized-client-api.d.ts +161 -0
- package/dist/lib/standardized-client-api.js +791 -0
- package/dist/lib/startup-init.d.ts +40 -0
- package/dist/lib/startup-init.js +257 -0
- package/dist/lib/test-aware-get-token.d.ts +2 -0
- package/dist/lib/test-aware-get-token.js +86 -0
- package/dist/lib/token-expiry.d.ts +14 -0
- package/dist/lib/token-expiry.js +39 -0
- package/dist/lib/token-lifecycle.d.ts +78 -0
- package/dist/lib/token-lifecycle.js +360 -0
- package/dist/lib/types/api-responses.d.ts +128 -0
- package/dist/lib/types/api-responses.js +171 -0
- package/dist/lib/user-agent-parser.d.ts +50 -0
- package/dist/lib/user-agent-parser.js +220 -0
- package/dist/logging/api/admin-analytics.d.ts +3 -0
- package/dist/logging/api/admin-analytics.js +45 -0
- package/dist/logging/api/audit-log.d.ts +3 -0
- package/dist/logging/api/audit-log.js +52 -0
- package/dist/logging/components/AdminAnalyticsLayout.d.ts +10 -0
- package/dist/logging/components/AdminAnalyticsLayout.js +11 -0
- package/dist/logging/components/AuditLogViewer.d.ts +7 -0
- package/dist/logging/components/AuditLogViewer.js +51 -0
- package/dist/logging/components/ErrorMetricsCard.d.ts +7 -0
- package/dist/logging/components/ErrorMetricsCard.js +16 -0
- package/dist/logging/components/HealthMetricsCard.d.ts +7 -0
- package/dist/logging/components/HealthMetricsCard.js +19 -0
- package/dist/logging/hooks/useAdminAnalytics.d.ts +24 -0
- package/dist/logging/hooks/useAdminAnalytics.js +22 -0
- package/dist/logging/hooks/useAuditLog.d.ts +6 -0
- package/dist/logging/hooks/useAuditLog.js +25 -0
- package/dist/logging/hooks/useErrorMetrics.d.ts +6 -0
- package/dist/logging/hooks/useErrorMetrics.js +38 -0
- package/dist/logging/hooks/useHealthMetrics.d.ts +6 -0
- package/dist/logging/hooks/useHealthMetrics.js +41 -0
- package/dist/logging/index.d.ts +11 -0
- package/dist/logging/index.js +40 -0
- package/dist/logging/types/analytics.d.ts +68 -0
- package/dist/logging/types/analytics.js +3 -0
- package/dist/logging/types/audit.d.ts +29 -0
- package/dist/logging/types/audit.js +2 -0
- package/dist/logging/types/index.d.ts +2 -0
- package/dist/logging/types/index.js +19 -0
- package/dist/middleware/auth-decision.d.ts +33 -0
- package/dist/middleware/auth-decision.js +65 -0
- package/dist/middleware/create-middleware.d.ts +102 -0
- package/dist/middleware/create-middleware.js +469 -0
- package/dist/middleware/rbac-check.d.ts +51 -0
- package/dist/middleware/rbac-check.js +219 -0
- package/dist/middleware/twofa-presets.d.ts +134 -0
- package/dist/middleware/twofa-presets.js +175 -0
- package/dist/models/DecodedAccessToken.d.ts +17 -0
- package/dist/models/DecodedAccessToken.js +2 -0
- package/dist/models/SessionModel.d.ts +122 -0
- package/dist/models/SessionModel.js +136 -0
- package/dist/pages/admin-login/page.d.ts +31 -0
- package/dist/pages/admin-login/page.js +73 -0
- package/dist/pages/admin-page-permissions/PagePermissionsAdminPage.d.ts +18 -0
- package/dist/pages/admin-page-permissions/PagePermissionsAdminPage.js +276 -0
- package/dist/pages/admin-page-permissions/index.d.ts +6 -0
- package/dist/pages/admin-page-permissions/index.js +13 -0
- package/dist/pages/admin-roles/RolesAdminPage.d.ts +16 -0
- package/dist/pages/admin-roles/RolesAdminPage.js +261 -0
- package/dist/pages/admin-roles/index.d.ts +8 -0
- package/dist/pages/admin-roles/index.js +15 -0
- package/dist/pages/admin-roles/modals.d.ts +72 -0
- package/dist/pages/admin-roles/modals.js +154 -0
- package/dist/pages/client-admin/ClientSiteAdminPage.d.ts +79 -0
- package/dist/pages/client-admin/ClientSiteAdminPage.js +179 -0
- package/dist/pages/client-admin/index.d.ts +32 -0
- package/dist/pages/client-admin/index.js +37 -0
- package/dist/pages/coming-soon/page.d.ts +8 -0
- package/dist/pages/coming-soon/page.js +28 -0
- package/dist/pages/login/page.d.ts +22 -0
- package/dist/pages/login/page.js +230 -0
- package/dist/pages/profile/EnhancedProfilePage.d.ts +13 -0
- package/dist/pages/profile/EnhancedProfilePage.js +150 -0
- package/dist/pages/profile/index.d.ts +8 -0
- package/dist/pages/profile/index.js +16 -0
- package/dist/pages/profile/page.d.ts +19 -0
- package/dist/pages/profile/page.js +47 -0
- package/dist/pages/recovery/page.d.ts +1 -0
- package/dist/pages/recovery/page.js +142 -0
- package/dist/pages/roles/MyRolesPage.d.ts +24 -0
- package/dist/pages/roles/MyRolesPage.js +71 -0
- package/dist/pages/roles/components.d.ts +63 -0
- package/dist/pages/roles/components.js +108 -0
- package/dist/pages/roles/index.d.ts +8 -0
- package/dist/pages/roles/index.js +19 -0
- package/dist/pages/security/EnhancedSecurityPage.d.ts +14 -0
- package/dist/pages/security/EnhancedSecurityPage.js +248 -0
- package/dist/pages/security/index.d.ts +8 -0
- package/dist/pages/security/index.js +16 -0
- package/dist/pages/security/page.d.ts +21 -0
- package/dist/pages/security/page.js +212 -0
- package/dist/pages/settings/EnhancedSettingsPage.d.ts +46 -0
- package/dist/pages/settings/EnhancedSettingsPage.js +231 -0
- package/dist/pages/settings/index.d.ts +8 -0
- package/dist/pages/settings/index.js +16 -0
- package/dist/pages/settings/page.d.ts +7 -0
- package/dist/pages/settings/page.js +26 -0
- package/dist/pages/showcase/ShowcasePage.d.ts +13 -0
- package/dist/pages/showcase/ShowcasePage.js +142 -0
- package/dist/pages/showcase/index.d.ts +12 -0
- package/dist/pages/showcase/index.js +17 -0
- package/dist/pages/test-env/EmergencyLogoutPage.d.ts +14 -0
- package/dist/pages/test-env/EmergencyLogoutPage.js +99 -0
- package/dist/pages/test-env/JwtInspectPage.d.ts +14 -0
- package/dist/pages/test-env/JwtInspectPage.js +116 -0
- package/dist/pages/test-env/RefreshTokenPage.d.ts +15 -0
- package/dist/pages/test-env/RefreshTokenPage.js +93 -0
- package/dist/pages/test-env/TestEnvPage.d.ts +13 -0
- package/dist/pages/test-env/TestEnvPage.js +51 -0
- package/dist/pages/test-env/index.d.ts +24 -0
- package/dist/pages/test-env/index.js +32 -0
- package/dist/pages/verify-code/page.d.ts +30 -0
- package/dist/pages/verify-code/page.js +412 -0
- package/dist/routes/account/index.d.ts +28 -0
- package/dist/routes/account/index.js +71 -0
- package/dist/routes/account/masked-info.d.ts +33 -0
- package/dist/routes/account/masked-info.js +39 -0
- package/dist/routes/account/send-code.d.ts +37 -0
- package/dist/routes/account/send-code.js +42 -0
- package/dist/routes/account/update-phone.d.ts +13 -0
- package/dist/routes/account/update-phone.js +17 -0
- package/dist/routes/account/verify-email.d.ts +38 -0
- package/dist/routes/account/verify-email.js +43 -0
- package/dist/routes/account/verify-sms.d.ts +38 -0
- package/dist/routes/account/verify-sms.js +43 -0
- package/dist/routes/auth/index.d.ts +19 -0
- package/dist/routes/auth/index.js +64 -0
- package/dist/routes/auth/logout.d.ts +31 -0
- package/dist/routes/auth/logout.js +98 -0
- package/dist/routes/auth/nextauth.d.ts +22 -0
- package/dist/routes/auth/nextauth.js +40 -0
- package/dist/routes/auth/refresh.d.ts +30 -0
- package/dist/routes/auth/refresh.js +51 -0
- package/dist/routes/auth/session.d.ts +43 -0
- package/dist/routes/auth/session.js +157 -0
- package/dist/routes/auth/settings.d.ts +25 -0
- package/dist/routes/auth/settings.js +55 -0
- package/dist/routes/auth/viability.d.ts +52 -0
- package/dist/routes/auth/viability.js +190 -0
- package/dist/routes/index.d.ts +12 -0
- package/dist/routes/index.js +54 -0
- package/dist/routes/session/index.d.ts +6 -0
- package/dist/routes/session/index.js +10 -0
- package/dist/routes/session/refresh-viability.d.ts +16 -0
- package/dist/routes/session/refresh-viability.js +20 -0
- package/dist/server/auth-guard.d.ts +46 -0
- package/dist/server/auth-guard.js +128 -0
- package/dist/server/auth.d.ts +50 -0
- package/dist/server/auth.js +62 -0
- package/dist/server/decode-session.d.ts +30 -0
- package/dist/server/decode-session.js +78 -0
- package/dist/server/slim-middleware.d.ts +23 -0
- package/dist/server/slim-middleware.js +89 -0
- package/dist/server/with-auth.d.ts +33 -0
- package/dist/server/with-auth.js +59 -0
- package/dist/services/signalrActivityService.d.ts +44 -0
- package/dist/services/signalrActivityService.js +257 -0
- package/dist/stores/authStore.d.ts +154 -0
- package/dist/stores/authStore.js +1527 -0
- package/dist/theme/ThemeProvider.d.ts +14 -0
- package/dist/theme/ThemeProvider.js +28 -0
- package/dist/theme/default.d.ts +8 -0
- package/dist/theme/default.js +33 -0
- package/dist/theme/index.d.ts +15 -0
- package/dist/theme/index.js +25 -0
- package/dist/theme/types.d.ts +56 -0
- package/dist/theme/types.js +8 -0
- package/dist/theme/useTheme.d.ts +60 -0
- package/dist/theme/useTheme.js +63 -0
- package/dist/theme/utils.d.ts +13 -0
- package/dist/theme/utils.js +39 -0
- package/dist/types/api.d.ts +134 -0
- package/dist/types/api.js +44 -0
- package/dist/types/auth.d.ts +19 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/logging.d.ts +42 -0
- package/dist/types/logging.js +2 -0
- package/dist/types/recovery.d.ts +48 -0
- package/dist/types/recovery.js +2 -0
- package/dist/types/security.d.ts +1 -0
- package/dist/types/security.js +2 -0
- package/dist/utils/api.d.ts +85 -0
- package/dist/utils/api.js +287 -0
- package/dist/utils/circuitBreaker.d.ts +43 -0
- package/dist/utils/circuitBreaker.js +91 -0
- package/dist/utils/error-message.d.ts +1 -0
- package/dist/utils/error-message.js +103 -0
- package/dist/utils/layout/reservedSpace.d.ts +59 -0
- package/dist/utils/layout/reservedSpace.js +102 -0
- package/dist/utils/logout.d.ts +14 -0
- package/dist/utils/logout.js +32 -0
- package/dist/vibe/client.d.ts +261 -0
- package/dist/vibe/client.js +445 -0
- package/dist/vibe/enterprise-auth.d.ts +106 -0
- package/dist/vibe/enterprise-auth.js +173 -0
- package/dist/vibe/errors.d.ts +83 -0
- package/dist/vibe/errors.js +146 -0
- package/dist/vibe/generic.d.ts +234 -0
- package/dist/vibe/generic.js +369 -0
- package/dist/vibe/hooks/index.d.ts +169 -0
- package/dist/vibe/hooks/index.js +252 -0
- package/dist/vibe/index.d.ts +25 -0
- package/dist/vibe/index.js +72 -0
- package/dist/vibe/sessions.d.ts +161 -0
- package/dist/vibe/sessions.js +391 -0
- package/dist/vibe/types.d.ts +353 -0
- package/dist/vibe/types.js +315 -0
- package/package.json +1 -1
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Themed Security Page for @payez/next-mvp
|
|
4
|
+
*
|
|
5
|
+
* DEPENDENCIES: Only React, Next.js, next-auth, React Query, and Tailwind CSS
|
|
6
|
+
* NO shadcn/ui or other UI library required!
|
|
7
|
+
*
|
|
8
|
+
* FEATURES:
|
|
9
|
+
* - Security summary (2FA status, email status, phone status)
|
|
10
|
+
* - Change password form with policy validation
|
|
11
|
+
* - Themeable styling via ThemeProvider
|
|
12
|
+
* - Uses React Query for data fetching (matches website-membership pattern)
|
|
13
|
+
*
|
|
14
|
+
* USAGE:
|
|
15
|
+
* 1. Import from @payez/next-mvp/pages/security
|
|
16
|
+
* 2. Wrap your app with ThemeProvider to customize branding
|
|
17
|
+
* 3. Create API routes at:
|
|
18
|
+
* - src/app/api/account/profile/route.ts
|
|
19
|
+
* - src/app/api/account/change-password/route.ts
|
|
20
|
+
* - src/app/api/account/validate-password/route.ts
|
|
21
|
+
*/
|
|
22
|
+
'use client';
|
|
23
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
26
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
27
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
28
|
+
}
|
|
29
|
+
Object.defineProperty(o, k2, desc);
|
|
30
|
+
}) : (function(o, m, k, k2) {
|
|
31
|
+
if (k2 === undefined) k2 = k;
|
|
32
|
+
o[k2] = m[k];
|
|
33
|
+
}));
|
|
34
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
35
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
36
|
+
}) : function(o, v) {
|
|
37
|
+
o["default"] = v;
|
|
38
|
+
});
|
|
39
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
40
|
+
var ownKeys = function(o) {
|
|
41
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
42
|
+
var ar = [];
|
|
43
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
44
|
+
return ar;
|
|
45
|
+
};
|
|
46
|
+
return ownKeys(o);
|
|
47
|
+
};
|
|
48
|
+
return function (mod) {
|
|
49
|
+
if (mod && mod.__esModule) return mod;
|
|
50
|
+
var result = {};
|
|
51
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
52
|
+
__setModuleDefault(result, mod);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
})();
|
|
56
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
+
exports.default = SecurityPage;
|
|
58
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
59
|
+
const react_1 = __importStar(require("react"));
|
|
60
|
+
const useProfile_1 = require("../../hooks/useProfile");
|
|
61
|
+
const usePasswordValidation_1 = require("../../hooks/usePasswordValidation");
|
|
62
|
+
const useTheme_1 = require("../../theme/useTheme");
|
|
63
|
+
// Inline PasswordStrengthMeter component
|
|
64
|
+
function PasswordStrengthMeter({ score, failedRequirements, tip, isDarkMode = false, }) {
|
|
65
|
+
const getStrengthColor = (s) => {
|
|
66
|
+
if (s >= 4)
|
|
67
|
+
return 'bg-green-500';
|
|
68
|
+
if (s >= 3)
|
|
69
|
+
return 'bg-yellow-500';
|
|
70
|
+
if (s >= 2)
|
|
71
|
+
return 'bg-orange-500';
|
|
72
|
+
return 'bg-red-500';
|
|
73
|
+
};
|
|
74
|
+
const getStrengthLabel = (s) => {
|
|
75
|
+
if (s >= 4)
|
|
76
|
+
return 'Strong';
|
|
77
|
+
if (s >= 3)
|
|
78
|
+
return 'Good';
|
|
79
|
+
if (s >= 2)
|
|
80
|
+
return 'Fair';
|
|
81
|
+
if (s >= 1)
|
|
82
|
+
return 'Weak';
|
|
83
|
+
return 'Very Weak';
|
|
84
|
+
};
|
|
85
|
+
const mutedTextClass = isDarkMode ? 'text-slate-400' : 'text-gray-500';
|
|
86
|
+
const barBgClass = isDarkMode ? 'bg-slate-600' : 'bg-gray-200';
|
|
87
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: `flex-1 h-2 rounded-full overflow-hidden ${barBgClass}`, children: (0, jsx_runtime_1.jsx)("div", { className: `h-full transition-all duration-300 ${getStrengthColor(score)}`, style: { width: `${Math.min(score * 20, 100)}%` } }) }), (0, jsx_runtime_1.jsx)("span", { className: `text-xs w-16 ${mutedTextClass}`, children: getStrengthLabel(score) })] }), failedRequirements.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: `text-xs space-y-1 ${mutedTextClass}`, children: failedRequirements.map((req, i) => ((0, jsx_runtime_1.jsxs)("li", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-red-400", children: "\u00D7" }), " ", req] }, i))) })), tip && ((0, jsx_runtime_1.jsx)("p", { className: "text-xs text-blue-400", children: tip }))] }));
|
|
88
|
+
}
|
|
89
|
+
// Inline PasswordPolicyChecklist component
|
|
90
|
+
function PasswordPolicyChecklist({ policy, password, isDarkMode = false, }) {
|
|
91
|
+
const checks = react_1.default.useMemo(() => {
|
|
92
|
+
const list = [];
|
|
93
|
+
const minLen = typeof policy?.min_length === 'number' && policy.min_length > 0 ? policy.min_length : 8;
|
|
94
|
+
list.push({ label: `At least ${minLen} characters`, ok: (password?.length || 0) >= minLen });
|
|
95
|
+
if (policy?.require_uppercase)
|
|
96
|
+
list.push({ label: 'One uppercase letter (A-Z)', ok: /[A-Z]/.test(password || '') });
|
|
97
|
+
if (policy?.require_lowercase)
|
|
98
|
+
list.push({ label: 'One lowercase letter (a-z)', ok: /[a-z]/.test(password || '') });
|
|
99
|
+
if (policy?.require_digit)
|
|
100
|
+
list.push({ label: 'One digit (0-9)', ok: /\d/.test(password || '') });
|
|
101
|
+
if (policy?.require_special)
|
|
102
|
+
list.push({ label: 'One special character (!@#$% etc.)', ok: /[^A-Za-z0-9]/.test(password || '') });
|
|
103
|
+
return list;
|
|
104
|
+
}, [policy, password]);
|
|
105
|
+
const mutedTextClass = isDarkMode ? 'text-slate-400' : 'text-gray-500';
|
|
106
|
+
const successTextClass = 'text-green-400';
|
|
107
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "space-y-1 text-xs", children: checks.map((c, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [c.ok ? ((0, jsx_runtime_1.jsx)("span", { className: successTextClass, children: "\u2713" })) : ((0, jsx_runtime_1.jsx)("span", { className: mutedTextClass, children: "\u25CB" })), (0, jsx_runtime_1.jsx)("span", { className: c.ok ? successTextClass : mutedTextClass, children: c.label })] }, i))) }));
|
|
108
|
+
}
|
|
109
|
+
function SecurityPage() {
|
|
110
|
+
const { data: profileData, isLoading: isProfileLoading } = (0, useProfile_1.useProfile)();
|
|
111
|
+
const layout = (0, useTheme_1.useLayout)();
|
|
112
|
+
const colors = (0, useTheme_1.useColors)();
|
|
113
|
+
// Determine if dark mode based on background color
|
|
114
|
+
const isDarkMode = colors?.background?.includes('slate-9') ||
|
|
115
|
+
colors?.background?.includes('gray-9') ||
|
|
116
|
+
colors?.background?.includes('dark') ||
|
|
117
|
+
colors?.card?.includes('slate-8') ||
|
|
118
|
+
colors?.card?.includes('gray-8');
|
|
119
|
+
// Password form state
|
|
120
|
+
const [formData, setFormData] = (0, react_1.useState)({
|
|
121
|
+
current_password: '',
|
|
122
|
+
new_password: '',
|
|
123
|
+
confirm_password: '',
|
|
124
|
+
});
|
|
125
|
+
const [showPasswords, setShowPasswords] = (0, react_1.useState)({
|
|
126
|
+
current: false,
|
|
127
|
+
new: false,
|
|
128
|
+
confirm: false,
|
|
129
|
+
});
|
|
130
|
+
const [submitting, setSubmitting] = (0, react_1.useState)(false);
|
|
131
|
+
const [error, setError] = (0, react_1.useState)('');
|
|
132
|
+
const [success, setSuccess] = (0, react_1.useState)('');
|
|
133
|
+
// Password validation
|
|
134
|
+
const { setPassword: validateNewPassword, isValid: newPasswordIsValid, score: newPasswordScore, failedRequirements, tip, policy, } = (0, usePasswordValidation_1.usePasswordValidation)({ debounceMs: 250 });
|
|
135
|
+
// Validate new password on change
|
|
136
|
+
(0, react_1.useEffect)(() => {
|
|
137
|
+
validateNewPassword(formData.new_password);
|
|
138
|
+
}, [formData.new_password, validateNewPassword]);
|
|
139
|
+
const passwordsMatch = formData.confirm_password.length > 0 && formData.new_password === formData.confirm_password;
|
|
140
|
+
const canSubmit = !submitting && newPasswordIsValid && passwordsMatch && formData.current_password.length > 0;
|
|
141
|
+
const handleSubmit = async (e) => {
|
|
142
|
+
e.preventDefault();
|
|
143
|
+
setError('');
|
|
144
|
+
setSuccess('');
|
|
145
|
+
if (!formData.current_password || !formData.new_password || !formData.confirm_password) {
|
|
146
|
+
setError('All fields are required');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (formData.new_password !== formData.confirm_password) {
|
|
150
|
+
setError('New password and confirmation do not match');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!newPasswordIsValid) {
|
|
154
|
+
setError('Please meet the password requirements before submitting');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
setSubmitting(true);
|
|
159
|
+
const response = await fetch('/api/account/change-password', {
|
|
160
|
+
method: 'POST',
|
|
161
|
+
headers: { 'Content-Type': 'application/json' },
|
|
162
|
+
body: JSON.stringify({
|
|
163
|
+
current_password: formData.current_password,
|
|
164
|
+
new_password: formData.new_password,
|
|
165
|
+
confirm_password: formData.confirm_password,
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
const result = await response.json();
|
|
169
|
+
if (!response.ok || !result.success) {
|
|
170
|
+
// Extract error message
|
|
171
|
+
let errorMsg = result.message || 'Failed to change password';
|
|
172
|
+
if (result.details?.value && Array.isArray(result.details.value) && result.details.value.length > 0) {
|
|
173
|
+
errorMsg = result.details.value[0].message || errorMsg;
|
|
174
|
+
}
|
|
175
|
+
else if (result.details?.message) {
|
|
176
|
+
errorMsg = result.details.message;
|
|
177
|
+
}
|
|
178
|
+
setError(errorMsg);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Success
|
|
182
|
+
setSuccess(result.message || 'Password changed successfully');
|
|
183
|
+
setFormData({ current_password: '', new_password: '', confirm_password: '' });
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
setError(err.message || 'Failed to change password');
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
setSubmitting(false);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
// Determine loading state colors before any early returns
|
|
193
|
+
const loadingTextClass = isDarkMode ? 'text-slate-400' : 'text-gray-500';
|
|
194
|
+
// Loading state
|
|
195
|
+
if (isProfileLoading) {
|
|
196
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "min-h-screen", children: (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center min-h-[400px]", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center space-y-4", children: [(0, jsx_runtime_1.jsxs)("svg", { className: `animate-spin h-8 w-8 ${loadingTextClass}`, viewBox: "0 0 24 24", fill: "none", children: [(0, jsx_runtime_1.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), (0, jsx_runtime_1.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12 a 8 8 0 0 1 8 -8 v 4 a 4 4 0 0 0 -4 4 H4 z" })] }), (0, jsx_runtime_1.jsx)("p", { className: loadingTextClass, children: "Loading security settings..." })] }) }) }));
|
|
197
|
+
}
|
|
198
|
+
// Theme-aware styling using colors from ThemeProvider
|
|
199
|
+
const cardBgClass = colors?.card || 'bg-white';
|
|
200
|
+
const borderClass = colors?.border || 'border-gray-200';
|
|
201
|
+
// Text colors based on dark/light mode
|
|
202
|
+
const textPrimaryClass = isDarkMode ? 'text-white' : 'text-gray-900';
|
|
203
|
+
const textSecondaryClass = isDarkMode ? 'text-slate-300' : 'text-gray-600';
|
|
204
|
+
const textMutedClass = isDarkMode ? 'text-slate-400' : 'text-gray-500';
|
|
205
|
+
// Input styling
|
|
206
|
+
const inputBgClass = isDarkMode ? 'bg-slate-800' : 'bg-white';
|
|
207
|
+
const inputBorderClass = isDarkMode ? 'border-slate-600' : 'border-gray-300';
|
|
208
|
+
const inputTextClass = isDarkMode ? 'text-white placeholder-slate-400' : 'text-gray-900 placeholder-gray-400';
|
|
209
|
+
// Elevated surfaces (status boxes)
|
|
210
|
+
const elevatedBgClass = isDarkMode ? 'bg-slate-700' : 'bg-gray-100';
|
|
211
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "min-h-screen", children: (0, jsx_runtime_1.jsxs)("div", { className: `${layout?.spacing || 'space-y-6'} ${layout?.maxWidth || 'max-w-4xl'} mx-auto ${layout?.padding || 'p-6'}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-between", children: (0, jsx_runtime_1.jsx)("h1", { className: `text-3xl font-bold ${textPrimaryClass}`, children: "Security" }) }), (0, jsx_runtime_1.jsxs)("div", { className: `rounded-lg shadow-sm border p-6 ${cardBgClass} ${borderClass}`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `text-xl font-semibold mb-4 ${textPrimaryClass}`, children: "Security Summary" }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: `p-4 rounded-lg ${elevatedBgClass}`, children: [(0, jsx_runtime_1.jsx)("p", { className: `text-sm font-medium mb-2 ${textSecondaryClass}`, children: "2FA Status" }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center space-x-2", children: (0, jsx_runtime_1.jsx)("span", { className: `inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${profileData?.two_factor_enabled ? 'bg-green-600 text-white' : 'bg-yellow-600 text-white'}`, children: profileData?.two_factor_enabled ? 'Enabled' : 'Not Active' }) }), !profileData?.two_factor_enabled && ((0, jsx_runtime_1.jsx)("p", { className: `text-xs mt-2 ${textMutedClass}`, children: "Self-service 2FA enrollment coming soon" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: `p-4 rounded-lg ${elevatedBgClass}`, children: [(0, jsx_runtime_1.jsx)("p", { className: `text-sm font-medium mb-2 ${textSecondaryClass}`, children: "Email Status" }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center space-x-2", children: (0, jsx_runtime_1.jsx)("span", { className: `inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${profileData?.email_confirmed ? 'bg-green-600 text-white' : 'bg-yellow-600 text-white'}`, children: profileData?.email_confirmed ? 'Verified' : 'Not Verified' }) }), (0, jsx_runtime_1.jsx)("p", { className: `text-xs mt-2 ${textPrimaryClass}`, children: profileData?.email })] }), (0, jsx_runtime_1.jsxs)("div", { className: `p-4 rounded-lg ${elevatedBgClass}`, children: [(0, jsx_runtime_1.jsx)("p", { className: `text-sm font-medium mb-2 ${textSecondaryClass}`, children: "Phone Status" }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center space-x-2", children: (0, jsx_runtime_1.jsx)("span", { className: `inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${profileData?.phone_confirmed ? 'bg-green-600 text-white' : 'bg-yellow-600 text-white'}`, children: profileData?.phone_confirmed ? 'Verified' : 'Not Verified' }) }), profileData?.phone_number && ((0, jsx_runtime_1.jsx)("p", { className: `text-xs mt-2 ${textPrimaryClass}`, children: profileData.phone_number }))] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: `rounded-lg shadow-sm border p-6 ${cardBgClass} ${borderClass}`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `text-xl font-semibold mb-4 ${textPrimaryClass}`, children: "Change Password" }), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium mb-2 ${textSecondaryClass}`, children: "Current Password" }), (0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)("input", { type: showPasswords.current ? 'text' : 'password', value: formData.current_password, onChange: e => setFormData({ ...formData, current_password: e.target.value }), className: `w-full px-3 py-2 rounded-md shadow-sm border focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${inputBgClass} ${inputBorderClass} ${inputTextClass}`, placeholder: "Enter current password", disabled: submitting, required: true }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setShowPasswords(p => ({ ...p, current: !p.current })), className: `absolute inset-y-0 right-2 flex items-center ${textMutedClass}`, children: showPasswords.current ? '👁️' : '👁️🗨️' })] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium mb-2 ${textSecondaryClass}`, children: "New Password" }), (0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)("input", { type: showPasswords.new ? 'text' : 'password', value: formData.new_password, onChange: e => setFormData({ ...formData, new_password: e.target.value }), className: `w-full px-3 py-2 rounded-md shadow-sm border focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${inputBgClass} ${inputBorderClass} ${inputTextClass}`, placeholder: "Enter new password", disabled: submitting, required: true }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setShowPasswords(p => ({ ...p, new: !p.new })), className: `absolute inset-y-0 right-2 flex items-center ${textMutedClass}`, children: showPasswords.new ? '👁️' : '👁️🗨️' })] }), formData.new_password && ((0, jsx_runtime_1.jsx)("div", { className: "mt-2", children: (0, jsx_runtime_1.jsx)(PasswordStrengthMeter, { score: newPasswordScore, failedRequirements: failedRequirements, tip: tip, isDarkMode: isDarkMode }) })), policy && formData.new_password && ((0, jsx_runtime_1.jsx)("div", { className: "mt-3", children: (0, jsx_runtime_1.jsx)(PasswordPolicyChecklist, { policy: policy, password: formData.new_password, isDarkMode: isDarkMode }) }))] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium mb-2 ${textSecondaryClass}`, children: "Confirm New Password" }), (0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)("input", { type: showPasswords.confirm ? 'text' : 'password', value: formData.confirm_password, onChange: e => setFormData({ ...formData, confirm_password: e.target.value }), className: `w-full px-3 py-2 rounded-md shadow-sm border focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${inputBgClass} ${inputBorderClass} ${inputTextClass}`, placeholder: "Confirm new password", disabled: submitting, required: true }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setShowPasswords(p => ({ ...p, confirm: !p.confirm })), className: `absolute inset-y-0 right-2 flex items-center ${textMutedClass}`, children: showPasswords.confirm ? '👁️' : '👁️🗨️' })] }), formData.confirm_password && !passwordsMatch && ((0, jsx_runtime_1.jsx)("p", { className: "mt-1 text-xs text-red-400", children: "Passwords do not match" })), formData.confirm_password && passwordsMatch && ((0, jsx_runtime_1.jsx)("p", { className: "mt-1 text-xs text-green-400", children: "Passwords match" }))] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "bg-red-900/30 border border-red-600 rounded-lg p-3", children: (0, jsx_runtime_1.jsx)("p", { className: "text-red-400 text-sm", children: error }) })), success && ((0, jsx_runtime_1.jsx)("div", { className: "bg-green-900/30 border border-green-600 rounded-lg p-3", children: (0, jsx_runtime_1.jsx)("p", { className: "text-green-400 text-sm", children: success }) })), (0, jsx_runtime_1.jsx)("div", { className: "pt-2", children: (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: !canSubmit, className: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed", children: submitting ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("svg", { className: "animate-spin -ml-1 mr-2 h-4 w-4 text-white", fill: "none", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), (0, jsx_runtime_1.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12 a 8 8 0 0 1 8 -8 v 4 a 4 4 0 0 0 -4 4 H4 z" })] }), "Changing..."] })) : ('Change Password') }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: `rounded-lg shadow-sm border p-6 ${cardBgClass} ${borderClass}`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `text-xl font-semibold mb-4 ${textPrimaryClass}`, children: "Additional Security Features" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: `flex items-center justify-between p-4 rounded-lg opacity-60 ${elevatedBgClass}`, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: `text-sm font-medium ${textPrimaryClass}`, children: "Active Sessions" }), (0, jsx_runtime_1.jsx)("p", { className: `text-sm ${textMutedClass}`, children: "View and manage your active login sessions" })] }), (0, jsx_runtime_1.jsx)("span", { className: `inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${isDarkMode ? 'bg-slate-600 text-slate-300' : 'bg-gray-200 text-gray-600'}`, children: "Coming Soon" })] }), (0, jsx_runtime_1.jsxs)("div", { className: `flex items-center justify-between p-4 rounded-lg opacity-60 ${elevatedBgClass}`, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: `text-sm font-medium ${textPrimaryClass}`, children: "2FA Management" }), (0, jsx_runtime_1.jsx)("p", { className: `text-sm ${textMutedClass}`, children: "Enable or configure two-factor authentication" })] }), (0, jsx_runtime_1.jsx)("span", { className: `inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${isDarkMode ? 'bg-slate-600 text-slate-300' : 'bg-gray-200 text-gray-600'}`, children: "Coming Soon" })] })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-center", children: (0, jsx_runtime_1.jsx)("a", { href: "/account/profile", className: `text-sm hover:underline ${textMutedClass}`, children: "\u2190 Back to Profile" }) })] }) }));
|
|
212
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Settings Page for @payez/next-mvp
|
|
3
|
+
*
|
|
4
|
+
* Implements BAPert's Member Self-Service spec with:
|
|
5
|
+
* - Appearance section (theme, compact mode)
|
|
6
|
+
* - Localization section (language, timezone, date format)
|
|
7
|
+
* - Notifications section (email and SMS preferences)
|
|
8
|
+
* - Privacy section (profile visibility, activity status)
|
|
9
|
+
*
|
|
10
|
+
* @see docs/specs/MEMBER_SELF_SERVICE_SPEC.md
|
|
11
|
+
*/
|
|
12
|
+
interface PreferencesData {
|
|
13
|
+
appearance?: {
|
|
14
|
+
theme?: 'light' | 'dark' | 'system';
|
|
15
|
+
compact_mode?: boolean;
|
|
16
|
+
};
|
|
17
|
+
localization?: {
|
|
18
|
+
language?: string;
|
|
19
|
+
timezone?: string;
|
|
20
|
+
timezone_display?: string;
|
|
21
|
+
date_format?: string;
|
|
22
|
+
};
|
|
23
|
+
notifications?: {
|
|
24
|
+
email_enabled?: boolean;
|
|
25
|
+
email_security_alerts?: boolean;
|
|
26
|
+
email_account_updates?: boolean;
|
|
27
|
+
email_product_news?: boolean;
|
|
28
|
+
email_marketing?: boolean;
|
|
29
|
+
sms_enabled?: boolean;
|
|
30
|
+
sms_security_alerts?: boolean;
|
|
31
|
+
};
|
|
32
|
+
privacy?: {
|
|
33
|
+
profile_visibility?: 'private' | 'team' | 'public';
|
|
34
|
+
show_activity_status?: boolean;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
interface EnhancedSettingsPageProps {
|
|
38
|
+
initialPreferences?: PreferencesData;
|
|
39
|
+
preferencesEndpoint?: string;
|
|
40
|
+
languagesEndpoint?: string;
|
|
41
|
+
timezonesEndpoint?: string;
|
|
42
|
+
onSave?: (preferences: PreferencesData) => Promise<void>;
|
|
43
|
+
onThemeChange?: (theme: 'light' | 'dark' | 'system') => void;
|
|
44
|
+
}
|
|
45
|
+
export default function EnhancedSettingsPage({ initialPreferences, preferencesEndpoint, languagesEndpoint, timezonesEndpoint, onSave, onThemeChange, }: EnhancedSettingsPageProps): import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced Settings Page for @payez/next-mvp
|
|
4
|
+
*
|
|
5
|
+
* Implements BAPert's Member Self-Service spec with:
|
|
6
|
+
* - Appearance section (theme, compact mode)
|
|
7
|
+
* - Localization section (language, timezone, date format)
|
|
8
|
+
* - Notifications section (email and SMS preferences)
|
|
9
|
+
* - Privacy section (profile visibility, activity status)
|
|
10
|
+
*
|
|
11
|
+
* @see docs/specs/MEMBER_SELF_SERVICE_SPEC.md
|
|
12
|
+
*/
|
|
13
|
+
'use client';
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.default = EnhancedSettingsPage;
|
|
16
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
17
|
+
const react_1 = require("react");
|
|
18
|
+
const useTheme_1 = require("../../theme/useTheme");
|
|
19
|
+
// Common languages for fallback
|
|
20
|
+
const DEFAULT_LANGUAGES = [
|
|
21
|
+
{ code: 'en', name: 'English (US)' },
|
|
22
|
+
{ code: 'en-GB', name: 'English (UK)' },
|
|
23
|
+
{ code: 'es', name: 'Spanish' },
|
|
24
|
+
{ code: 'fr', name: 'French' },
|
|
25
|
+
{ code: 'de', name: 'German' },
|
|
26
|
+
{ code: 'ja', name: 'Japanese' },
|
|
27
|
+
{ code: 'zh', name: 'Chinese (Simplified)' },
|
|
28
|
+
];
|
|
29
|
+
// Common timezones for fallback
|
|
30
|
+
const DEFAULT_TIMEZONES = [
|
|
31
|
+
{ id: 'America/Los_Angeles', display: 'Pacific Time (US)', offset: '-08:00' },
|
|
32
|
+
{ id: 'America/Denver', display: 'Mountain Time (US)', offset: '-07:00' },
|
|
33
|
+
{ id: 'America/Chicago', display: 'Central Time (US)', offset: '-06:00' },
|
|
34
|
+
{ id: 'America/New_York', display: 'Eastern Time (US)', offset: '-05:00' },
|
|
35
|
+
{ id: 'Europe/London', display: 'London', offset: '+00:00' },
|
|
36
|
+
{ id: 'Europe/Paris', display: 'Paris', offset: '+01:00' },
|
|
37
|
+
{ id: 'Europe/Berlin', display: 'Berlin', offset: '+01:00' },
|
|
38
|
+
{ id: 'Asia/Tokyo', display: 'Tokyo', offset: '+09:00' },
|
|
39
|
+
{ id: 'Asia/Shanghai', display: 'Shanghai', offset: '+08:00' },
|
|
40
|
+
{ id: 'Australia/Sydney', display: 'Sydney', offset: '+11:00' },
|
|
41
|
+
];
|
|
42
|
+
// Date format options
|
|
43
|
+
const DATE_FORMATS = [
|
|
44
|
+
{ value: 'MM/DD/YYYY', label: 'MM/DD/YYYY', example: '01/09/2026' },
|
|
45
|
+
{ value: 'DD/MM/YYYY', label: 'DD/MM/YYYY', example: '09/01/2026' },
|
|
46
|
+
{ value: 'YYYY-MM-DD', label: 'YYYY-MM-DD', example: '2026-01-09' },
|
|
47
|
+
];
|
|
48
|
+
// Toggle component
|
|
49
|
+
function Toggle({ enabled, onChange, disabled = false, isDark = true, }) {
|
|
50
|
+
return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => !disabled && onChange(!enabled), disabled: disabled, className: `
|
|
51
|
+
relative inline-flex h-6 w-11 items-center rounded-full transition-colors
|
|
52
|
+
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
|
|
53
|
+
${enabled ? 'bg-blue-600' : isDark ? 'bg-slate-600' : 'bg-gray-300'}
|
|
54
|
+
`, children: (0, jsx_runtime_1.jsx)("span", { className: `
|
|
55
|
+
inline-block h-4 w-4 transform rounded-full bg-white transition-transform
|
|
56
|
+
${enabled ? 'translate-x-6' : 'translate-x-1'}
|
|
57
|
+
` }) }));
|
|
58
|
+
}
|
|
59
|
+
// Section wrapper component
|
|
60
|
+
function SettingsSection({ title, children, isDark, }) {
|
|
61
|
+
const borderColor = isDark ? 'border-slate-700' : 'border-gray-200';
|
|
62
|
+
const titleColor = isDark ? 'text-gray-400' : 'text-gray-500';
|
|
63
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: `border-b ${borderColor} pb-6 mb-6 last:border-b-0`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `text-sm font-semibold uppercase tracking-wider ${titleColor} mb-4`, children: title }), children] }));
|
|
64
|
+
}
|
|
65
|
+
// Setting row component
|
|
66
|
+
function SettingRow({ label, description, children, isDark, }) {
|
|
67
|
+
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
|
|
68
|
+
const textMuted = isDark ? 'text-gray-400' : 'text-gray-500';
|
|
69
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between py-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-1", children: [(0, jsx_runtime_1.jsx)("p", { className: `font-medium ${textPrimary}`, children: label }), description && (0, jsx_runtime_1.jsx)("p", { className: `text-sm ${textMuted}`, children: description })] }), (0, jsx_runtime_1.jsx)("div", { className: "ml-4", children: children })] }));
|
|
70
|
+
}
|
|
71
|
+
// Select dropdown component
|
|
72
|
+
function Select({ value, onChange, options, isDark, }) {
|
|
73
|
+
const bgColor = isDark ? 'bg-slate-700' : 'bg-white';
|
|
74
|
+
const borderColor = isDark ? 'border-slate-600' : 'border-gray-300';
|
|
75
|
+
const textColor = isDark ? 'text-white' : 'text-gray-900';
|
|
76
|
+
return ((0, jsx_runtime_1.jsx)("select", { value: value, onChange: (e) => onChange(e.target.value), className: `
|
|
77
|
+
px-3 py-2 rounded-md border ${borderColor} ${bgColor} ${textColor}
|
|
78
|
+
focus:outline-none focus:ring-2 focus:ring-blue-500 min-w-[200px]
|
|
79
|
+
`, children: options.map((opt) => ((0, jsx_runtime_1.jsx)("option", { value: opt.value, children: opt.label }, opt.value))) }));
|
|
80
|
+
}
|
|
81
|
+
function EnhancedSettingsPage({ initialPreferences, preferencesEndpoint = '/api/v1/user/preferences', languagesEndpoint = '/api/v1/lookup/languages', timezonesEndpoint = '/api/v1/lookup/timezones', onSave, onThemeChange, }) {
|
|
82
|
+
const layout = (0, useTheme_1.useLayout)();
|
|
83
|
+
const colors = (0, useTheme_1.useColors)();
|
|
84
|
+
// Determine dark mode from theme colors
|
|
85
|
+
const isDark = colors?.background?.includes('slate-9') ||
|
|
86
|
+
colors?.background?.includes('gray-9') ||
|
|
87
|
+
colors?.card?.includes('slate-8');
|
|
88
|
+
// State
|
|
89
|
+
const [preferences, setPreferences] = (0, react_1.useState)(initialPreferences || {});
|
|
90
|
+
const [languages, setLanguages] = (0, react_1.useState)(DEFAULT_LANGUAGES);
|
|
91
|
+
const [timezones, setTimezones] = (0, react_1.useState)(DEFAULT_TIMEZONES);
|
|
92
|
+
const [loading, setLoading] = (0, react_1.useState)(!initialPreferences);
|
|
93
|
+
const [saving, setSaving] = (0, react_1.useState)(false);
|
|
94
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
95
|
+
const [successMessage, setSuccessMessage] = (0, react_1.useState)(null);
|
|
96
|
+
// Theme colors
|
|
97
|
+
const bgColor = isDark ? 'bg-slate-900' : 'bg-gray-50';
|
|
98
|
+
const cardBg = isDark ? 'bg-slate-800' : 'bg-white';
|
|
99
|
+
const borderColor = isDark ? 'border-slate-700' : 'border-gray-200';
|
|
100
|
+
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
|
|
101
|
+
const textMuted = isDark ? 'text-gray-400' : 'text-gray-500';
|
|
102
|
+
// Fetch preferences and lookups
|
|
103
|
+
(0, react_1.useEffect)(() => {
|
|
104
|
+
async function fetchData() {
|
|
105
|
+
try {
|
|
106
|
+
setLoading(true);
|
|
107
|
+
setError(null);
|
|
108
|
+
// Fetch preferences
|
|
109
|
+
const prefResponse = await fetch(preferencesEndpoint, { credentials: 'include' });
|
|
110
|
+
if (prefResponse.ok) {
|
|
111
|
+
const prefData = await prefResponse.json();
|
|
112
|
+
setPreferences(prefData);
|
|
113
|
+
}
|
|
114
|
+
// Fetch languages (optional)
|
|
115
|
+
try {
|
|
116
|
+
const langResponse = await fetch(languagesEndpoint, { credentials: 'include' });
|
|
117
|
+
if (langResponse.ok) {
|
|
118
|
+
const langData = await langResponse.json();
|
|
119
|
+
if (langData.languages)
|
|
120
|
+
setLanguages(langData.languages);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Use defaults
|
|
125
|
+
}
|
|
126
|
+
// Fetch timezones (optional)
|
|
127
|
+
try {
|
|
128
|
+
const tzResponse = await fetch(timezonesEndpoint, { credentials: 'include' });
|
|
129
|
+
if (tzResponse.ok) {
|
|
130
|
+
const tzData = await tzResponse.json();
|
|
131
|
+
if (tzData.timezones)
|
|
132
|
+
setTimezones(tzData.timezones);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Use defaults
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
setError('Failed to load settings');
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
setLoading(false);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (!initialPreferences) {
|
|
147
|
+
fetchData();
|
|
148
|
+
}
|
|
149
|
+
}, [preferencesEndpoint, languagesEndpoint, timezonesEndpoint, initialPreferences]);
|
|
150
|
+
// Update preference value
|
|
151
|
+
const updatePreference = (0, react_1.useCallback)((section, key, value) => {
|
|
152
|
+
setPreferences((prev) => ({
|
|
153
|
+
...prev,
|
|
154
|
+
[section]: {
|
|
155
|
+
...prev[section],
|
|
156
|
+
[key]: value,
|
|
157
|
+
},
|
|
158
|
+
}));
|
|
159
|
+
}, []);
|
|
160
|
+
// Save preferences
|
|
161
|
+
const handleSave = (0, react_1.useCallback)(async () => {
|
|
162
|
+
try {
|
|
163
|
+
setSaving(true);
|
|
164
|
+
setError(null);
|
|
165
|
+
setSuccessMessage(null);
|
|
166
|
+
if (onSave) {
|
|
167
|
+
await onSave(preferences);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const response = await fetch(preferencesEndpoint, {
|
|
171
|
+
method: 'PUT',
|
|
172
|
+
headers: { 'Content-Type': 'application/json' },
|
|
173
|
+
credentials: 'include',
|
|
174
|
+
body: JSON.stringify(preferences),
|
|
175
|
+
});
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
const data = await response.json();
|
|
178
|
+
throw new Error(data.message || 'Failed to save settings');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
setSuccessMessage('Settings saved successfully');
|
|
182
|
+
setTimeout(() => setSuccessMessage(null), 3000);
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
setError(err instanceof Error ? err.message : 'Failed to save settings');
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
setSaving(false);
|
|
189
|
+
}
|
|
190
|
+
}, [preferences, preferencesEndpoint, onSave]);
|
|
191
|
+
// Handle theme change
|
|
192
|
+
const handleThemeChange = (0, react_1.useCallback)((theme) => {
|
|
193
|
+
updatePreference('appearance', 'theme', theme);
|
|
194
|
+
onThemeChange?.(theme);
|
|
195
|
+
}, [updatePreference, onThemeChange]);
|
|
196
|
+
// Loading state
|
|
197
|
+
if (loading) {
|
|
198
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: `min-h-screen ${bgColor} flex items-center justify-center`, children: (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center space-y-4", children: [(0, jsx_runtime_1.jsxs)("svg", { className: "animate-spin h-8 w-8 text-blue-500", viewBox: "0 0 24 24", fill: "none", children: [(0, jsx_runtime_1.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), (0, jsx_runtime_1.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })] }), (0, jsx_runtime_1.jsx)("p", { className: textMuted, children: "Loading settings..." })] }) }));
|
|
199
|
+
}
|
|
200
|
+
const currentTheme = preferences.appearance?.theme || 'system';
|
|
201
|
+
const compactMode = preferences.appearance?.compact_mode || false;
|
|
202
|
+
const currentLanguage = preferences.localization?.language || 'en';
|
|
203
|
+
const currentTimezone = preferences.localization?.timezone || 'America/Los_Angeles';
|
|
204
|
+
const currentDateFormat = preferences.localization?.date_format || 'MM/DD/YYYY';
|
|
205
|
+
const emailEnabled = preferences.notifications?.email_enabled ?? true;
|
|
206
|
+
const smsEnabled = preferences.notifications?.sms_enabled ?? false;
|
|
207
|
+
const profileVisibility = preferences.privacy?.profile_visibility || 'team';
|
|
208
|
+
const showActivityStatus = preferences.privacy?.show_activity_status ?? true;
|
|
209
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: `min-h-screen ${bgColor}`, children: (0, jsx_runtime_1.jsxs)("div", { className: `max-w-2xl mx-auto ${layout?.padding || 'p-6'}`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-6", children: [(0, jsx_runtime_1.jsx)("h1", { className: `text-3xl font-bold ${textPrimary}`, children: "Settings" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleSave, disabled: saving, className: `
|
|
210
|
+
px-4 py-2 rounded-md font-medium transition-colors
|
|
211
|
+
${saving ? 'opacity-50 cursor-not-allowed' : ''}
|
|
212
|
+
bg-blue-600 text-white hover:bg-blue-700
|
|
213
|
+
`, children: saving ? 'Saving...' : 'Save Changes' })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 p-3 rounded-md bg-red-500/10 border border-red-500/50 text-red-500", children: error })), successMessage && ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 p-3 rounded-md bg-green-500/10 border border-green-500/50 text-green-500", children: successMessage })), (0, jsx_runtime_1.jsxs)("div", { className: `${cardBg} rounded-lg shadow-lg border ${borderColor} p-6`, children: [(0, jsx_runtime_1.jsxs)(SettingsSection, { title: "Appearance", isDark: isDark, children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium ${textMuted} mb-2`, children: "Theme" }), (0, jsx_runtime_1.jsx)("div", { className: "flex gap-2", children: ['light', 'dark', 'system'].map((theme) => ((0, jsx_runtime_1.jsx)("button", { onClick: () => handleThemeChange(theme), className: `
|
|
214
|
+
px-4 py-2 rounded-md capitalize transition-colors
|
|
215
|
+
${currentTheme === theme
|
|
216
|
+
? 'bg-blue-600 text-white'
|
|
217
|
+
: isDark
|
|
218
|
+
? 'bg-slate-700 text-gray-300 hover:bg-slate-600'
|
|
219
|
+
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'}
|
|
220
|
+
`, children: theme }, theme))) })] }), (0, jsx_runtime_1.jsx)(SettingRow, { label: "Compact Mode", description: "Reduce spacing and padding for denser layouts", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: compactMode, onChange: (value) => updatePreference('appearance', 'compact_mode', value), isDark: isDark }) })] }), (0, jsx_runtime_1.jsx)(SettingsSection, { title: "Localization", isDark: isDark, children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium ${textMuted} mb-2`, children: "Language" }), (0, jsx_runtime_1.jsx)(Select, { value: currentLanguage, onChange: (value) => updatePreference('localization', 'language', value), options: languages.map((l) => ({ value: l.code, label: l.name })), isDark: isDark })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium ${textMuted} mb-2`, children: "Timezone" }), (0, jsx_runtime_1.jsx)(Select, { value: currentTimezone, onChange: (value) => updatePreference('localization', 'timezone', value), options: timezones.map((tz) => ({ value: tz.id, label: `${tz.display} (${tz.offset})` })), isDark: isDark }), preferences.localization?.timezone_display && ((0, jsx_runtime_1.jsxs)("p", { className: `mt-1 text-sm ${textMuted}`, children: ["Currently: ", preferences.localization.timezone_display] }))] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium ${textMuted} mb-2`, children: "Date Format" }), (0, jsx_runtime_1.jsx)(Select, { value: currentDateFormat, onChange: (value) => updatePreference('localization', 'date_format', value), options: DATE_FORMATS.map((df) => ({ value: df.value, label: df.label })), isDark: isDark }), (0, jsx_runtime_1.jsxs)("p", { className: `mt-1 text-sm ${textMuted}`, children: ["Example: ", DATE_FORMATS.find((df) => df.value === currentDateFormat)?.example] })] })] }) }), (0, jsx_runtime_1.jsxs)(SettingsSection, { title: "Notifications", isDark: isDark, children: [(0, jsx_runtime_1.jsx)(SettingRow, { label: "Email Notifications", description: "Receive updates and alerts via email", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: emailEnabled, onChange: (value) => updatePreference('notifications', 'email_enabled', value), isDark: isDark }) }), emailEnabled && ((0, jsx_runtime_1.jsxs)("div", { className: `ml-6 border-l-2 ${borderColor} pl-4 space-y-2`, children: [(0, jsx_runtime_1.jsx)(SettingRow, { label: "Security alerts", description: "Login from new device, etc.", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: preferences.notifications?.email_security_alerts ?? true, onChange: (value) => updatePreference('notifications', 'email_security_alerts', value), isDark: isDark }) }), (0, jsx_runtime_1.jsx)(SettingRow, { label: "Account updates", description: "Password expiry, etc.", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: preferences.notifications?.email_account_updates ?? true, onChange: (value) => updatePreference('notifications', 'email_account_updates', value), isDark: isDark }) }), (0, jsx_runtime_1.jsx)(SettingRow, { label: "Product news and tips", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: preferences.notifications?.email_product_news ?? false, onChange: (value) => updatePreference('notifications', 'email_product_news', value), isDark: isDark }) }), (0, jsx_runtime_1.jsx)(SettingRow, { label: "Marketing and promotions", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: preferences.notifications?.email_marketing ?? false, onChange: (value) => updatePreference('notifications', 'email_marketing', value), isDark: isDark }) })] })), (0, jsx_runtime_1.jsx)(SettingRow, { label: "SMS Notifications", description: "Receive urgent alerts via text message", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: smsEnabled, onChange: (value) => updatePreference('notifications', 'sms_enabled', value), isDark: isDark }) }), smsEnabled && ((0, jsx_runtime_1.jsx)("div", { className: `ml-6 border-l-2 ${borderColor} pl-4`, children: (0, jsx_runtime_1.jsx)(SettingRow, { label: "Security alerts only", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: preferences.notifications?.sms_security_alerts ?? true, onChange: (value) => updatePreference('notifications', 'sms_security_alerts', value), isDark: isDark }) }) }))] }), (0, jsx_runtime_1.jsxs)(SettingsSection, { title: "Privacy", isDark: isDark, children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsx)("label", { className: `block text-sm font-medium ${textMuted} mb-2`, children: "Profile Visibility" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2", children: [
|
|
221
|
+
{ value: 'private', label: 'Private', description: 'Only you can see your profile' },
|
|
222
|
+
{ value: 'team', label: 'Team', description: 'Team members can see your profile' },
|
|
223
|
+
{ value: 'public', label: 'Public', description: 'Anyone can see your profile' },
|
|
224
|
+
].map((option) => ((0, jsx_runtime_1.jsxs)("label", { className: `flex items-center p-3 rounded-md cursor-pointer transition-colors ${profileVisibility === option.value
|
|
225
|
+
? isDark
|
|
226
|
+
? 'bg-blue-600/20 border border-blue-500'
|
|
227
|
+
: 'bg-blue-50 border border-blue-500'
|
|
228
|
+
: isDark
|
|
229
|
+
? 'bg-slate-700 hover:bg-slate-600'
|
|
230
|
+
: 'bg-gray-50 hover:bg-gray-100'}`, children: [(0, jsx_runtime_1.jsx)("input", { type: "radio", name: "profileVisibility", value: option.value, checked: profileVisibility === option.value, onChange: (e) => updatePreference('privacy', 'profile_visibility', e.target.value), className: "mr-3" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: `font-medium ${textPrimary}`, children: option.label }), (0, jsx_runtime_1.jsx)("p", { className: `text-sm ${textMuted}`, children: option.description })] })] }, option.value))) })] }), (0, jsx_runtime_1.jsx)(SettingRow, { label: "Activity Status", description: "Show when you're active to team members", isDark: isDark, children: (0, jsx_runtime_1.jsx)(Toggle, { enabled: showActivityStatus, onChange: (value) => updatePreference('privacy', 'show_activity_status', value), isDark: isDark }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-6 flex justify-between", children: [(0, jsx_runtime_1.jsx)("a", { href: "/account/security", className: `text-sm hover:underline ${textMuted}`, children: "\u2190 Security Settings" }), (0, jsx_runtime_1.jsx)("a", { href: "/account/profile", className: `text-sm hover:underline ${textMuted}`, children: "Back to Profile \u2192" })] })] }) }));
|
|
231
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Page exports
|
|
3
|
+
*
|
|
4
|
+
* - SettingsPage: Basic settings display (legacy)
|
|
5
|
+
* - EnhancedSettingsPage: Full-featured settings with appearance, localization, notifications, privacy
|
|
6
|
+
*/
|
|
7
|
+
export { default as SettingsPage } from './page';
|
|
8
|
+
export { default as EnhancedSettingsPage } from './EnhancedSettingsPage';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Settings Page exports
|
|
4
|
+
*
|
|
5
|
+
* - SettingsPage: Basic settings display (legacy)
|
|
6
|
+
* - EnhancedSettingsPage: Full-featured settings with appearance, localization, notifications, privacy
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.EnhancedSettingsPage = exports.SettingsPage = void 0;
|
|
13
|
+
var page_1 = require("./page");
|
|
14
|
+
Object.defineProperty(exports, "SettingsPage", { enumerable: true, get: function () { return __importDefault(page_1).default; } });
|
|
15
|
+
var EnhancedSettingsPage_1 = require("./EnhancedSettingsPage");
|
|
16
|
+
Object.defineProperty(exports, "EnhancedSettingsPage", { enumerable: true, get: function () { return __importDefault(EnhancedSettingsPage_1).default; } });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Basic Settings Page
|
|
4
|
+
*
|
|
5
|
+
* A simpler settings page that can be customized.
|
|
6
|
+
* For the full-featured version, use EnhancedSettingsPage.
|
|
7
|
+
*/
|
|
8
|
+
'use client';
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.default = SettingsPage;
|
|
11
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
12
|
+
const useTheme_1 = require("../../theme/useTheme");
|
|
13
|
+
function SettingsPage() {
|
|
14
|
+
const layout = (0, useTheme_1.useLayout)();
|
|
15
|
+
const colors = (0, useTheme_1.useColors)();
|
|
16
|
+
// Determine dark mode from theme colors
|
|
17
|
+
const isDark = colors?.background?.includes('slate-9') ||
|
|
18
|
+
colors?.background?.includes('gray-9') ||
|
|
19
|
+
colors?.card?.includes('slate-8');
|
|
20
|
+
const bgColor = isDark ? 'bg-slate-900' : 'bg-gray-50';
|
|
21
|
+
const cardBg = isDark ? 'bg-slate-800' : 'bg-white';
|
|
22
|
+
const borderColor = isDark ? 'border-slate-700' : 'border-gray-200';
|
|
23
|
+
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
|
|
24
|
+
const textMuted = isDark ? 'text-gray-400' : 'text-gray-500';
|
|
25
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: `min-h-screen ${bgColor}`, children: (0, jsx_runtime_1.jsxs)("div", { className: `max-w-2xl mx-auto ${layout?.padding || 'p-6'}`, children: [(0, jsx_runtime_1.jsx)("h1", { className: `text-3xl font-bold ${textPrimary} mb-6`, children: "Settings" }), (0, jsx_runtime_1.jsx)("div", { className: `${cardBg} rounded-lg shadow-lg border ${borderColor} p-6`, children: (0, jsx_runtime_1.jsx)("p", { className: textMuted, children: "Settings page content goes here. Use EnhancedSettingsPage for a full-featured implementation." }) }), (0, jsx_runtime_1.jsx)("div", { className: "mt-6 text-center", children: (0, jsx_runtime_1.jsx)("a", { href: "/account/profile", className: `text-sm hover:underline ${textMuted}`, children: "Back to Profile" }) })] }) }));
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Showcase Page
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates MVP capabilities with interactive examples.
|
|
5
|
+
*
|
|
6
|
+
* Usage in consuming app:
|
|
7
|
+
* ```typescript
|
|
8
|
+
* // app/showcase/page.tsx
|
|
9
|
+
* export { ShowcasePage as default } from '@payez/next-mvp/pages/showcase';
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare function ShowcasePage(): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export default ShowcasePage;
|