xertica-ui 2.5.2 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +687 -656
- package/README.md +482 -482
- package/assets/xertica-logo.svg +37 -37
- package/assets/xertica-x-logo.svg +20 -20
- package/bin/cli.ts +1293 -1256
- package/bin/generate-tokens.ts +256 -262
- package/bin/language-config.test.ts +32 -0
- package/bin/language-config.ts +36 -11
- package/components/Introduction.mdx +121 -121
- package/components/assistant/code-block/CodeBlock.tsx +7 -6
- package/components/assistant/code-block/code-block.mdx +38 -38
- package/components/assistant/code-block/code-block.test.tsx +2 -1
- package/components/assistant/formatted-document/FormattedDocument.tsx +3 -0
- package/components/assistant/formatted-document/formatted-document.mdx +31 -31
- package/components/assistant/formatted-document/formatted-document.test.tsx +5 -4
- package/components/assistant/markdown-message/MarkdownMessage.tsx +1 -1
- package/components/assistant/markdown-message/markdown-message.mdx +44 -44
- package/components/assistant/modern-chat-input/modern-chat-input.mdx +71 -71
- package/components/assistant/modern-chat-input/modern-chat-input.test.tsx +3 -2
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +1 -1
- package/components/assistant/xertica-assistant/types.ts +3 -2
- package/components/assistant/xertica-assistant/use-assistant.ts +5 -4
- package/components/assistant/xertica-assistant/xertica-assistant.mdx +66 -66
- package/components/assistant/xertica-assistant/xertica-assistant.test.tsx +2 -1
- package/components/blocks/card-patterns/card-patterns.mdx +123 -123
- package/components/brand/branding/branding.mdx +27 -27
- package/components/brand/language-selector/language-selector.mdx +126 -126
- package/components/brand/theme-toggle/theme-toggle.mdx +47 -47
- package/components/brand/theme-toggle/theme-toggle.test.tsx +6 -2
- package/components/brand/xertica-logo/xertica-logo.mdx +56 -56
- package/components/brand/xertica-orbe/xertica-orbe.mdx +38 -38
- package/components/brand/xertica-provider/XerticaProvider.tsx +112 -112
- package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
- package/components/brand/xertica-provider/xertica-provider.test.tsx +25 -13
- package/components/brand/xertica-xlogo/xertica-xlogo.mdx +55 -55
- package/components/examples/DrawingMapExample.tsx +1 -4
- package/components/layout/header/header.mdx +117 -117
- package/components/layout/header/header.test.tsx +2 -1
- package/components/layout/sidebar/sidebar.mdx +99 -99
- package/components/layout/sidebar/sidebar.stories.tsx +1033 -1033
- package/components/layout/sidebar/sidebar.test.tsx +2 -1
- package/components/layout/sidebar/sidebar.tsx +1509 -1501
- package/components/media/audio-player/AudioPlayer.mdx +67 -67
- package/components/media/audio-player/AudioPlayer.test.tsx +2 -1
- package/components/media/floating-media-wrapper.mdx +74 -74
- package/components/media/video-player/VideoPlayer.mdx +102 -102
- package/components/media/video-player/VideoPlayer.test.tsx +3 -2
- package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
- package/components/pages/forgot-password-page/forgot-password-page.mdx +60 -60
- package/components/pages/forgot-password-page/forgot-password-page.test.tsx +2 -1
- package/components/pages/home-content/HomeContent.tsx +2 -3
- package/components/pages/home-content/home-content.mdx +62 -62
- package/components/pages/home-page/HomePage.stories.tsx +8 -15
- package/components/pages/home-page/home-page.mdx +53 -53
- package/components/pages/home-page/home-page.test.tsx +2 -1
- package/components/pages/login-page/LoginPage.mdx +31 -31
- package/components/pages/login-page/LoginPage.tsx +218 -218
- package/components/pages/login-page/login-page.test.tsx +2 -1
- package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -243
- package/components/pages/reset-password-page/reset-password-page.mdx +63 -63
- package/components/pages/template-content/TemplateContent.tsx +2 -3
- package/components/pages/template-content/template-content.mdx +61 -61
- package/components/pages/template-page/TemplatePage.stories.tsx +32 -32
- package/components/pages/template-page/template-page.mdx +53 -53
- package/components/pages/template-page/template-page.test.tsx +2 -1
- package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
- package/components/pages/verify-email-page/verify-email-page.mdx +55 -55
- package/components/public-api-smoke.test.tsx +10 -6
- package/components/shared/assistant-utils.ts +3 -2
- package/components/shared/navigation.ts +2 -2
- package/components/ui/accordion/accordion.mdx +29 -29
- package/components/ui/alert/alert.mdx +29 -29
- package/components/ui/alert-dialog/alert-dialog.mdx +26 -26
- package/components/ui/aspect-ratio/aspect-ratio.mdx +25 -25
- package/components/ui/assistant-chart/AssistantChart.tsx +8 -2
- package/components/ui/assistant-chart/assistant-chart.mdx +25 -25
- package/components/ui/avatar/avatar.mdx +26 -26
- package/components/ui/badge/badge.mdx +28 -28
- package/components/ui/breadcrumb/breadcrumb.mdx +26 -26
- package/components/ui/button/button.mdx +29 -29
- package/components/ui/calendar/calendar.mdx +26 -26
- package/components/ui/card/card.mdx +26 -26
- package/components/ui/carousel/carousel.mdx +26 -26
- package/components/ui/chart/chart.mdx +26 -26
- package/components/ui/chart/chart.test.tsx +178 -178
- package/components/ui/chart/chart.tsx +2252 -2245
- package/components/ui/checkbox/checkbox.mdx +26 -26
- package/components/ui/collapsible/collapsible.mdx +25 -25
- package/components/ui/command/command.mdx +26 -26
- package/components/ui/context-menu/context-menu.mdx +26 -26
- package/components/ui/dialog/dialog.mdx +26 -26
- package/components/ui/drawer/drawer.mdx +26 -26
- package/components/ui/dropdown-menu/dropdown-menu.mdx +26 -26
- package/components/ui/empty/empty.mdx +26 -26
- package/components/ui/file-upload/file-upload.mdx +26 -26
- package/components/ui/form/form.mdx +20 -20
- package/components/ui/google-maps-loader/google-maps-loader.mdx +68 -68
- package/components/ui/hover-card/hover-card.mdx +26 -26
- package/components/ui/input/input.mdx +29 -29
- package/components/ui/input-otp/input-otp.mdx +26 -26
- package/components/ui/label/label.mdx +25 -25
- package/components/ui/map/map.mdx +26 -26
- package/components/ui/map/map.tsx +6 -1
- package/components/ui/menubar/menubar.mdx +26 -26
- package/components/ui/navigation-menu/navigation-menu.mdx +26 -26
- package/components/ui/notification-badge/notification-badge.mdx +26 -26
- package/components/ui/page-header/page-header.mdx +44 -44
- package/components/ui/pagination/pagination.mdx +26 -26
- package/components/ui/popover/popover.mdx +26 -26
- package/components/ui/progress/progress.mdx +25 -25
- package/components/ui/radio-group/radio-group.mdx +26 -26
- package/components/ui/rating/rating.mdx +26 -26
- package/components/ui/resizable/resizable.mdx +26 -26
- package/components/ui/resizable/resizable.tsx +13 -8
- package/components/ui/rich-text-editor/rich-text-editor.mdx +47 -47
- package/components/ui/route-map/route-map.mdx +26 -26
- package/components/ui/scroll-area/scroll-area.mdx +25 -25
- package/components/ui/search/search.mdx +27 -27
- package/components/ui/select/select.mdx +26 -26
- package/components/ui/separator/separator.mdx +25 -25
- package/components/ui/sheet/sheet.mdx +26 -26
- package/components/ui/simple-map/simple-map.mdx +25 -25
- package/components/ui/skeleton/skeleton.mdx +25 -25
- package/components/ui/slider/slider.mdx +26 -26
- package/components/ui/sonner/sonner.mdx +26 -26
- package/components/ui/stats-card/stats-card.mdx +26 -26
- package/components/ui/stats-card/stats-card.stories.tsx +117 -117
- package/components/ui/stats-card/stats-card.tsx +109 -109
- package/components/ui/stepper/stepper.mdx +26 -26
- package/components/ui/switch/switch.mdx +25 -25
- package/components/ui/table/table.mdx +27 -27
- package/components/ui/tabs/tabs.mdx +26 -26
- package/components/ui/textarea/textarea.mdx +25 -25
- package/components/ui/timeline/timeline.mdx +26 -26
- package/components/ui/toggle/toggle.mdx +26 -26
- package/components/ui/toggle-group/toggle-group.mdx +26 -26
- package/components/ui/tooltip/tooltip.mdx +26 -26
- package/components/ui/tree-view/tree-view.mdx +26 -26
- package/components.json +511 -511
- package/contexts/BrandColorsContext.tsx +282 -282
- package/contexts/i18n-singleton.test.tsx +57 -0
- package/contexts/theme-data.ts +391 -391
- package/dist/{AssistantChart-DMJJ_Amf.js → AssistantChart-BMNSA_Pk.js} +5 -5
- package/dist/{AssistantChart-D0A1FPYt.cjs → AssistantChart-BzM7plyc.cjs} +150 -114
- package/dist/{AssistantChart-BXU1ACnh.js → AssistantChart-C842evTi.js} +134 -240
- package/dist/{AssistantChart-BZTPJ5dP.cjs → AssistantChart-CVF2uh37.cjs} +5 -5
- package/dist/{AssistantChart-COGiOV-g.cjs → AssistantChart-JooMdVQU.cjs} +17 -7
- package/dist/{AssistantChart-CWX1OWNM.js → AssistantChart-KHS-tp-L.js} +17 -7
- package/dist/{BrandColorsContext-BwY-b6M4.cjs → BrandColorsContext-B4_81eas.cjs} +2 -2
- package/dist/{BrandColorsContext-BMRJ04Wf.js → BrandColorsContext-DbK5LnQ_.js} +2 -2
- package/dist/{CodeBlock-CjeFavqV.js → CodeBlock-DiKO8ocT.js} +11 -11
- package/dist/{CodeBlock-CV6dtsTM.cjs → CodeBlock-ZYThr7Kn.cjs} +12 -9
- package/dist/{XerticaXLogo-mqjoBiLI.js → LanguageSelector-CmTj3lWq.js} +85 -82
- package/dist/{XerticaXLogo-BX3ueACh.js → LanguageSelector-DxW6o7bt.js} +81 -81
- package/dist/{XerticaXLogo-uQgwns_E.cjs → LanguageSelector-Sw73qvWV.cjs} +84 -81
- package/dist/{ThemeContext-BgclCB35.js → ThemeContext-BGeh_Kdr.js} +290 -212
- package/dist/{ThemeContext-BblcjQup.cjs → ThemeContext-D50irx5T.cjs} +291 -205
- package/dist/{VerifyEmailPage-C_Zk6Gen.cjs → VerifyEmailPage-B6bOrybJ.cjs} +17 -17
- package/dist/{VerifyEmailPage-B31mCrMc.js → VerifyEmailPage-BRE5Fz59.js} +8 -8
- package/dist/{VerifyEmailPage-BJjAMUTW.js → VerifyEmailPage-BcCluouh.js} +151 -78
- package/dist/VerifyEmailPage-Bx1sr0uQ.cjs +3298 -0
- package/dist/{VerifyEmailPage-X14vhdyl.js → VerifyEmailPage-DUYyXCX9.js} +12 -12
- package/dist/VerifyEmailPage-DXXMHbzq.js +3289 -0
- package/dist/{VerifyEmailPage-u_Dn7t1U.cjs → VerifyEmailPage-DpYtFk35.cjs} +21 -21
- package/dist/{VerifyEmailPage-Cyl55sJb.js → VerifyEmailPage-NXKWW3Dk.js} +134 -64
- package/dist/{VerifyEmailPage-Bv8Ah_TK.cjs → VerifyEmailPage-QrCz4Wqr.cjs} +143 -73
- package/dist/{VerifyEmailPage-CkBYfsNy.cjs → VerifyEmailPage-ZmQra0Wi.cjs} +160 -87
- package/dist/{XerticaProvider-BErr83Bg.js → XerticaProvider-BF3q_myt.js} +5 -4
- package/dist/{XerticaProvider-CeS5G_n5.cjs → XerticaProvider-C_JSOz1U.cjs} +2 -2
- package/dist/{XerticaProvider-CwOkHxiT.cjs → XerticaProvider-D5zjrqZq.cjs} +5 -4
- package/dist/{XerticaProvider-ra2NciRq.js → XerticaProvider-KTGl4Cn1.js} +2 -2
- package/dist/{alert-dialog-DqlRW_An.js → alert-dialog-BrpwXKwS.js} +3 -3
- package/dist/{alert-dialog-DhwPioBa.cjs → alert-dialog-CZU1Zase.cjs} +3 -3
- package/dist/{alert-dialog-KpoabzJb.js → alert-dialog-ClRoLH7l.js} +40 -56
- package/dist/{alert-dialog-B4M3vQKS.cjs → alert-dialog-DBBqvU-V.cjs} +53 -38
- package/dist/assistant.cjs.js +2 -2
- package/dist/assistant.es.js +2 -2
- package/dist/brand.cjs.js +6 -6
- package/dist/brand.es.js +2 -2
- package/dist/cli.js +63 -21
- package/dist/components/assistant/code-block/CodeBlock.d.ts +2 -1
- package/dist/components/assistant/formatted-document/FormattedDocument.d.ts +2 -1
- package/dist/components/assistant/markdown-message/MarkdownMessage.d.ts +2 -1
- package/dist/components/assistant/modern-chat-input/ModernChatInput.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantCollapsedView.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantConversationList.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantHeader.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantMessageBubble.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantTabBar.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.d.ts +2 -1
- package/dist/components/assistant/xertica-assistant/types.d.ts +3 -2
- package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +1 -1
- package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +2 -1
- package/dist/components/blocks/card-patterns/ActivityCard.d.ts +1 -1
- package/dist/components/blocks/card-patterns/ActivityCardSkeleton.d.ts +1 -1
- package/dist/components/blocks/card-patterns/FeatureCard.d.ts +1 -1
- package/dist/components/blocks/card-patterns/FeatureCardSkeleton.d.ts +1 -1
- package/dist/components/blocks/card-patterns/NotificationCard.d.ts +1 -1
- package/dist/components/blocks/card-patterns/NotificationCardSkeleton.d.ts +1 -1
- package/dist/components/blocks/card-patterns/ProfileCard.d.ts +1 -1
- package/dist/components/blocks/card-patterns/ProfileCardSkeleton.d.ts +1 -1
- package/dist/components/blocks/card-patterns/ProjectCard.d.ts +1 -1
- package/dist/components/blocks/card-patterns/ProjectCardSkeleton.d.ts +1 -1
- package/dist/components/blocks/card-patterns/QuickActionCard.d.ts +1 -1
- package/dist/components/blocks/card-patterns/QuickActionCardSkeleton.d.ts +1 -1
- package/dist/components/brand/language-selector/LanguageSelector.d.ts +2 -1
- package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +2 -1
- package/dist/components/brand/xertica-logo/XerticaLogo.d.ts +2 -1
- package/dist/components/brand/xertica-orbe/XerticaOrbe.d.ts +2 -1
- package/dist/components/brand/xertica-provider/XerticaProvider.d.ts +1 -1
- package/dist/components/brand/xertica-xlogo/XerticaXLogo.d.ts +2 -1
- package/dist/components/examples/DrawingMapExample.d.ts +2 -1
- package/dist/components/examples/FilterableMapExample.d.ts +1 -1
- package/dist/components/examples/MapShowcase.d.ts +2 -1
- package/dist/components/examples/SimpleFilterableMap.d.ts +2 -1
- package/dist/components/figma/ImageWithFallback.d.ts +1 -1
- package/dist/components/layout/header/header.d.ts +1 -1
- package/dist/components/layout/sidebar/sidebar.d.ts +25 -13
- package/dist/components/media/FloatingMediaWrapper.d.ts +1 -1
- package/dist/components/media/audio-player/AudioPlayer.d.ts +2 -1
- package/dist/components/media/video-player/VideoPlayer.d.ts +2 -1
- package/dist/components/pages/forgot-password-page/ForgotPasswordPage.d.ts +2 -1
- package/dist/components/pages/home-content/HomeContent.d.ts +2 -1
- package/dist/components/pages/home-page/HomePage.d.ts +2 -1
- package/dist/components/pages/login-page/LoginPage.d.ts +2 -1
- package/dist/components/pages/reset-password-page/ResetPasswordPage.d.ts +2 -1
- package/dist/components/pages/template-content/TemplateContent.d.ts +2 -1
- package/dist/components/pages/template-page/TemplatePage.d.ts +2 -1
- package/dist/components/pages/verify-email-page/VerifyEmailPage.d.ts +2 -1
- package/dist/components/shared/CustomTooltipContent.d.ts +1 -1
- package/dist/components/shared/assistant-utils.d.ts +3 -2
- package/dist/components/shared/error-boundary.d.ts +4 -4
- package/dist/components/shared/error-fallbacks.d.ts +4 -3
- package/dist/components/shared/navigation.d.ts +6 -2
- package/dist/components/ui/accordion/accordion.d.ts +4 -4
- package/dist/components/ui/alert/alert.d.ts +3 -3
- package/dist/components/ui/alert-dialog/alert-dialog.d.ts +10 -10
- package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts +1 -1
- package/dist/components/ui/assistant-chart/AssistantChart.d.ts +4 -3
- package/dist/components/ui/avatar/avatar.d.ts +3 -3
- package/dist/components/ui/badge/badge.d.ts +1 -1
- package/dist/components/ui/breadcrumb/breadcrumb.d.ts +7 -7
- package/dist/components/ui/calendar/calendar.d.ts +2 -2
- package/dist/components/ui/card/card.d.ts +7 -7
- package/dist/components/ui/carousel/carousel.d.ts +5 -5
- package/dist/components/ui/chart/chart.d.ts +16 -16
- package/dist/components/ui/collapsible/collapsible.d.ts +3 -3
- package/dist/components/ui/command/command.d.ts +9 -9
- package/dist/components/ui/context-menu/context-menu.d.ts +15 -15
- package/dist/components/ui/dialog/dialog.d.ts +9 -9
- package/dist/components/ui/drawer/drawer.d.ts +10 -10
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +15 -15
- package/dist/components/ui/form/form.d.ts +7 -7
- package/dist/components/ui/google-maps-loader/google-maps-loader.d.ts +3 -3
- package/dist/components/ui/hover-card/hover-card.d.ts +3 -3
- package/dist/components/ui/input-otp/input-otp.d.ts +4 -4
- package/dist/components/ui/label/label.d.ts +1 -1
- package/dist/components/ui/menubar/menubar.d.ts +16 -16
- package/dist/components/ui/navigation-menu/navigation-menu.d.ts +8 -8
- package/dist/components/ui/page-header/page-header.d.ts +3 -3
- package/dist/components/ui/pagination/pagination.d.ts +7 -7
- package/dist/components/ui/popover/popover.d.ts +4 -4
- package/dist/components/ui/progress/progress.d.ts +1 -1
- package/dist/components/ui/resizable/resizable.d.ts +11 -7
- package/dist/components/ui/rich-text-editor/rich-text-editor.d.ts +1 -1
- package/dist/components/ui/scroll-area/scroll-area.d.ts +2 -2
- package/dist/components/ui/separator/separator.d.ts +1 -1
- package/dist/components/ui/sheet/sheet.d.ts +10 -10
- package/dist/components/ui/skeleton/skeleton.d.ts +1 -1
- package/dist/components/ui/sonner/sonner.d.ts +2 -1
- package/dist/components/ui/stats-card/stats-card-skeleton.d.ts +1 -1
- package/dist/components/ui/table/table.d.ts +8 -8
- package/dist/components/ui/tabs/tabs.d.ts +4 -4
- package/dist/components/ui/tooltip/tooltip.d.ts +4 -4
- package/dist/contexts/ApiKeyContext.d.ts +2 -2
- package/dist/contexts/AssistenteContext.d.ts +1 -1
- package/dist/contexts/AuthContext.d.ts +1 -1
- package/dist/contexts/LanguageContext.d.ts +2 -2
- package/dist/contexts/LayoutContext.d.ts +2 -2
- package/dist/contexts/ThemeContext.d.ts +1 -1
- package/dist/features/assistant/hooks/useAssistantConfig.d.ts +1 -1
- package/dist/features/home/hooks/useDashboardStats.d.ts +1 -1
- package/dist/features/home/hooks/useFeatureCards.d.ts +1 -1
- package/dist/features/home/hooks/useTeamMembers.d.ts +1 -1
- package/dist/{google-maps-loader-BCe58h9D.js → google-maps-loader-BOug999f.js} +0 -4
- package/dist/{google-maps-loader-casMyxlo.cjs → google-maps-loader-DfeBRI8Q.cjs} +0 -5
- package/dist/hooks.cjs.js +2 -2
- package/dist/hooks.es.js +2 -2
- package/dist/{index-9GWd0qxq.cjs → index-BQjx1Mdf.cjs} +1 -1
- package/dist/index-Bei5DzAL.js +6 -0
- package/dist/index.cjs.js +18 -18
- package/dist/index.es.js +12 -12
- package/dist/{input-cc-PTD4R.js → input-B0_vbA3g.js} +3 -61
- package/dist/{input-C_UiS2Py.cjs → input-ByYuOv8A.cjs} +1 -62
- package/dist/layout.cjs.js +1 -1
- package/dist/layout.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/{rich-text-editor-DxO1Hz3a.cjs → rich-text-editor-BuqSu718.cjs} +70 -5
- package/dist/{rich-text-editor-DqLICivI.js → rich-text-editor-CV8FtA_l.js} +68 -6
- package/dist/{rich-text-editor-DloeW0wc.js → rich-text-editor-DV1SixzE.js} +61 -3
- package/dist/{rich-text-editor-B2CKz7nx.cjs → rich-text-editor-DnSDglzW.cjs} +63 -2
- package/dist/{sidebar-BS1p2V7t.cjs → sidebar-BGJ0j567.cjs} +367 -9
- package/dist/{sidebar-3XyzjVBw.js → sidebar-BI6mZlC8.js} +364 -6
- package/dist/{sidebar-DyYvgyBj.cjs → sidebar-BtmotOg-.cjs} +367 -9
- package/dist/{sidebar-Duermn32.js → sidebar-D3EgGVxF.js} +77 -63
- package/dist/{sidebar-CLmIjgNd.cjs → sidebar-DDTqMGnR.cjs} +80 -66
- package/dist/{sidebar-B4ZWaMrE.js → sidebar-I7EXyf5D.js} +364 -6
- package/dist/ui.cjs.js +7 -7
- package/dist/ui.es.js +5 -5
- package/dist/{xertica-assistant-QFUnv5I2.cjs → xertica-assistant-BrF9jScR.cjs} +4 -4
- package/dist/{xertica-assistant-BbgzsgsG.js → xertica-assistant-CJVnvMqU.js} +55 -45
- package/dist/{xertica-assistant-d2qs2Vd9.cjs → xertica-assistant-CKPtc1z5.cjs} +58 -40
- package/dist/{xertica-assistant-CyikE3N_.js → xertica-assistant-CsBsxTsI.js} +2 -2
- package/dist/{xertica-assistant-CIaUlbIt.cjs → xertica-assistant-DER0brPQ.cjs} +6 -5
- package/dist/{xertica-assistant-B1NaSFFj.js → xertica-assistant-DQCjpk5M.js} +4 -3
- package/dist/{xertica-assistant-B687qEPU.js → xertica-assistant-Dk-9AJzw.js} +16 -7
- package/dist/{xertica-assistant-sOHwTgIP.cjs → xertica-assistant-DxhIKvuY.cjs} +18 -9
- package/dist/xertica-ui.css +2 -2
- package/docs/components/audio-player.md +1 -1
- package/docs/components/sidebar.md +331 -331
- package/docs/components/stats-card.md +138 -138
- package/docs/components/toggle.md +12 -0
- package/docs/doc-audit.md +35 -229
- package/docs/i18n.md +31 -10
- package/docs/llms.md +6 -4
- package/llms-compact.txt +444 -444
- package/llms-full.txt +12144 -12144
- package/llms.txt +187 -187
- package/package.json +223 -219
- package/scripts/a11y-audit.mjs +162 -162
- package/scripts/fix-stories.cjs +19 -19
- package/styles/globals.css +0 -1
- package/styles/xertica/base.css +8 -0
- package/styles/xertica/tokens.css +240 -240
- package/templates/.env.example +2 -2
- package/templates/.prettierignore +4 -4
- package/templates/.prettierrc +10 -10
- package/templates/guidelines/Guidelines.md +865 -865
- package/templates/index.html +13 -13
- package/templates/package.json +69 -69
- package/templates/src/app/components/AuthGuard.tsx +11 -0
- package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
- package/templates/src/features/home/ui/HomeContent.tsx +2 -3
- package/templates/src/features/settings/index.ts +2 -0
- package/templates/src/features/settings/ui/SettingsContent.tsx +134 -0
- package/templates/src/features/template/ui/TemplateContent.tsx +2 -3
- package/templates/src/i18n.ts +36 -13
- package/templates/src/locales/en/pages/settings.json +15 -0
- package/templates/src/locales/es/pages/settings.json +15 -0
- package/templates/src/locales/pt-BR/pages/settings.json +15 -0
- package/templates/src/pages/SettingsPage.tsx +28 -0
- package/templates/src/shared/config/navigation.ts +2 -2
- package/templates/src/styles/xertica/tokens.css +240 -240
- package/templates/vite.config.d.ts +2 -2
- package/templates/vite.config.js +20 -20
- package/utils/gemini.ts +2 -2
- package/dist/AssistantChart-9w31gdAb.cjs +0 -3363
- package/dist/AssistantChart-BAudAfne.cjs +0 -3591
- package/dist/AssistantChart-BAx9VQvb.cjs +0 -3374
- package/dist/AssistantChart-BP8upjMk.js +0 -3565
- package/dist/AssistantChart-CVko2A1W.js +0 -3348
- package/dist/AssistantChart-CVzmmhx4.js +0 -3337
- package/dist/AssistantChart-CeU2dIb6.js +0 -3469
- package/dist/AssistantChart-DO5UuX4J.cjs +0 -3495
- package/dist/AudioPlayer-1ypwE2Wh.cjs +0 -936
- package/dist/AudioPlayer-BJ2IuRQW.cjs +0 -1275
- package/dist/AudioPlayer-BWDW6TN9.cjs +0 -1279
- package/dist/AudioPlayer-CM962GEh.js +0 -1280
- package/dist/AudioPlayer-CbZId7cj.cjs +0 -998
- package/dist/AudioPlayer-DU8zt8-z.js +0 -999
- package/dist/AudioPlayer-DuKXrCfy.js +0 -937
- package/dist/AudioPlayer-Xxma6_-H.js +0 -1276
- package/dist/BrandColorsContext-DLVJgtmH.js +0 -666
- package/dist/BrandColorsContext-DZT7JjeD.js +0 -659
- package/dist/BrandColorsContext-GUyFmkX0.cjs +0 -665
- package/dist/BrandColorsContext-awnBCmC4.cjs +0 -666
- package/dist/CodeBlock-C2ZUXt8V.js +0 -219
- package/dist/CodeBlock-C5oYnLQp.cjs +0 -218
- package/dist/CodeBlock-DuxdtN-l.js +0 -219
- package/dist/CodeBlock-POVYONvC.cjs +0 -218
- package/dist/CustomTooltipContent-BT6brkVJ.cjs +0 -49
- package/dist/CustomTooltipContent-CfOfikhq.js +0 -33
- package/dist/CustomTooltipContent-DHjkY0ww.js +0 -40
- package/dist/CustomTooltipContent-c_K-DWRr.cjs +0 -56
- package/dist/FeatureCard-9GhnlgL3.js +0 -336
- package/dist/FeatureCard-Bcb3Zi54.js +0 -302
- package/dist/FeatureCard-Cfs6Ishq.js +0 -485
- package/dist/FeatureCard-CkPd2psQ.cjs +0 -301
- package/dist/FeatureCard-Dkp-xmzM.cjs +0 -335
- package/dist/FeatureCard-ie3L8Fpr.cjs +0 -484
- package/dist/FeatureCardSkeleton-CAgu8stE.js +0 -27
- package/dist/FeatureCardSkeleton-mO3Bdm_V.cjs +0 -26
- package/dist/LanguageContext-BwhwC3G2.js +0 -657
- package/dist/LanguageContext-DvUt5jBg.cjs +0 -656
- package/dist/LayoutContext-BDmcZfMH.cjs +0 -84
- package/dist/LayoutContext-C4kKN9RV.cjs +0 -93
- package/dist/LayoutContext-CGEe1oPq.js +0 -94
- package/dist/LayoutContext-CwT5KLiW.cjs +0 -104
- package/dist/LayoutContext-DVLCsoQn.js +0 -105
- package/dist/LayoutContext-dbQvdC4O.js +0 -85
- package/dist/ThemeContext-BbBNoFTG.js +0 -735
- package/dist/ThemeContext-Bo-W2WZH.js +0 -1856
- package/dist/ThemeContext-CP3a0jxy.cjs +0 -1855
- package/dist/ThemeContext-Cmr8Ex8H.cjs +0 -734
- package/dist/ThemeContext-CpqYShLq.cjs +0 -324
- package/dist/ThemeContext-D3LzacmG.js +0 -188
- package/dist/ThemeContext-DQUOeziy.cjs +0 -1855
- package/dist/ThemeContext-Du2nE1PL.js +0 -325
- package/dist/ThemeContext-GeEBTJ3q.cjs +0 -1621
- package/dist/ThemeContext-JyLK9B1o.js +0 -1622
- package/dist/ThemeContext-RTy1m2Uq.js +0 -82
- package/dist/ThemeContext-U4dEYc6C.cjs +0 -187
- package/dist/ThemeContext-bSzuOit2.cjs +0 -81
- package/dist/ThemeContext-ept8jhXI.js +0 -1856
- package/dist/VerifyEmailPage-BE-L9mB7.js +0 -2828
- package/dist/VerifyEmailPage-BIBOKV7Z.js +0 -3214
- package/dist/VerifyEmailPage-BRSP-Pwt.cjs +0 -3196
- package/dist/VerifyEmailPage-Bae2cBXT.cjs +0 -2827
- package/dist/VerifyEmailPage-BiRm7Nh4.cjs +0 -3213
- package/dist/VerifyEmailPage-Bvfv8HVQ.js +0 -3214
- package/dist/VerifyEmailPage-CR7kb5df.cjs +0 -2827
- package/dist/VerifyEmailPage-C_ihbcth.js +0 -2828
- package/dist/VerifyEmailPage-CbgjOF0v.js +0 -2828
- package/dist/VerifyEmailPage-CdYPSJoO.js +0 -2828
- package/dist/VerifyEmailPage-D-FRj5TU.cjs +0 -3213
- package/dist/VerifyEmailPage-DF2ilhum.cjs +0 -3210
- package/dist/VerifyEmailPage-DMBh4NM9.cjs +0 -2827
- package/dist/VerifyEmailPage-DTtFfC-J.js +0 -3197
- package/dist/VerifyEmailPage-Dt7zgA4w.cjs +0 -2827
- package/dist/VerifyEmailPage-EhudUdqF.js +0 -3211
- package/dist/VerifyEmailPage-RrUApqBN.js +0 -3214
- package/dist/VerifyEmailPage-VoMI7MYH.cjs +0 -3213
- package/dist/VerifyEmailPage-hdB8JQGv.cjs +0 -3213
- package/dist/VerifyEmailPage-vYHbYK3q.js +0 -3214
- package/dist/XerticaOrbe-BCUVSPPB.cjs +0 -1924
- package/dist/XerticaOrbe-BGIB1CTK.js +0 -1355
- package/dist/XerticaOrbe-By8eEvR-.js +0 -1925
- package/dist/XerticaOrbe-FWGjBj0U.cjs +0 -1354
- package/dist/XerticaProvider-AChwphCO.cjs +0 -48
- package/dist/XerticaProvider-AbWlr7Af.cjs +0 -48
- package/dist/XerticaProvider-B8CaV7xu.cjs +0 -39
- package/dist/XerticaProvider-BITjgC5p.js +0 -39
- package/dist/XerticaProvider-BSyFrmC0.js +0 -49
- package/dist/XerticaProvider-By8q3Roe.cjs +0 -38
- package/dist/XerticaProvider-CUYJZc32.js +0 -49
- package/dist/XerticaProvider-CW9hpCdF.cjs +0 -39
- package/dist/XerticaProvider-CWgby5mY.js +0 -49
- package/dist/XerticaProvider-CWs6EwNa.js +0 -49
- package/dist/XerticaProvider-CiNKjMx1.cjs +0 -48
- package/dist/XerticaProvider-CjQAQPcn.cjs +0 -48
- package/dist/XerticaProvider-D5lLumH-.js +0 -49
- package/dist/XerticaProvider-DQtvJU7m.js +0 -40
- package/dist/XerticaProvider-DUOJg9iX.js +0 -49
- package/dist/XerticaProvider-Dl_b72_l.cjs +0 -51
- package/dist/XerticaProvider-qQUDop71.cjs +0 -48
- package/dist/XerticaProvider-siSt9uG2.js +0 -40
- package/dist/XerticaXLogo-8TTzBjHw.cjs +0 -251
- package/dist/XerticaXLogo-B2svDGZh.cjs +0 -251
- package/dist/XerticaXLogo-BWaag64t.js +0 -252
- package/dist/XerticaXLogo-CFuIlYFH.js +0 -252
- package/dist/XerticaXLogo-CU-U-GP4.cjs +0 -251
- package/dist/XerticaXLogo-ChryA6xj.js +0 -252
- package/dist/XerticaXLogo-CowGv7BC.js +0 -252
- package/dist/XerticaXLogo-CziKMQil.cjs +0 -242
- package/dist/XerticaXLogo-D8jf0SNv.cjs +0 -214
- package/dist/XerticaXLogo-DHz5SugF.js +0 -252
- package/dist/XerticaXLogo-DTee_y8X.cjs +0 -251
- package/dist/XerticaXLogo-DfUvz-lD.js +0 -243
- package/dist/XerticaXLogo-DzXKZBtG.js +0 -231
- package/dist/XerticaXLogo-fAJMy3H4.js +0 -215
- package/dist/XerticaXLogo-kslQ8Tk_.cjs +0 -251
- package/dist/XerticaXLogo-xWbElCZj.cjs +0 -230
- package/dist/alert-dialog-iDe5VE5o.js +0 -842
- package/dist/alert-dialog-yckpaOpy.cjs +0 -865
- package/dist/avatar-Cq5_E8r9.cjs +0 -78
- package/dist/avatar-CuYu2MKt.cjs +0 -72
- package/dist/avatar-Cxyofu1H.js +0 -56
- package/dist/avatar-DSBfJMRJ.js +0 -62
- package/dist/breadcrumb-CVzzzqfo.js +0 -103
- package/dist/breadcrumb-DIJ0X3Ot.js +0 -96
- package/dist/breadcrumb-DjSxkjlQ.cjs +0 -95
- package/dist/breadcrumb-DnDlQFg2.cjs +0 -102
- package/dist/button-0CXwCRTm.cjs +0 -85
- package/dist/button-Bnv9SvYK.cjs +0 -79
- package/dist/button-C6uvh0rV.js +0 -63
- package/dist/button-qkz7Icqf.js +0 -69
- package/dist/card-B8-Gl5DL.js +0 -73
- package/dist/card-Bv_c57KU.cjs +0 -72
- package/dist/card-DJTsYhLL.cjs +0 -89
- package/dist/card-fi8zAN-I.js +0 -90
- package/dist/dropdown-menu-B_uEXNc4.cjs +0 -220
- package/dist/dropdown-menu-CFuCssWA.js +0 -204
- package/dist/dropdown-menu-Ze1YZFyc.cjs +0 -247
- package/dist/dropdown-menu-nc_Lvg-u.js +0 -231
- package/dist/google-maps-loader-BVoVhUwA.js +0 -316
- package/dist/google-maps-loader-BqsYL48U.cjs +0 -285
- package/dist/google-maps-loader-DjJaYhV6.cjs +0 -316
- package/dist/google-maps-loader-t2IlYBzw.js +0 -286
- package/dist/index-B7A523O_.js +0 -8
- package/dist/index-BabBx2pa.js +0 -6
- package/dist/index-CkTUgOwX.js +0 -8
- package/dist/index-D3RLKRAs.cjs +0 -7
- package/dist/index-DmHhnb7a.cjs +0 -7
- package/dist/index.umd.js +0 -13712
- package/dist/input-CNFHVKvo.cjs +0 -145
- package/dist/input-CPl84zAx.cjs +0 -151
- package/dist/input-D-6IsAca.js +0 -133
- package/dist/input-wPYg0d0P.js +0 -127
- package/dist/progress-BLwqortq.cjs +0 -105
- package/dist/progress-Cs9i4DPx.js +0 -81
- package/dist/progress-D9mtsf6j.js +0 -89
- package/dist/progress-DDeuWPZw.cjs +0 -97
- package/dist/rich-text-editor-1UW3Y2JK.js +0 -2891
- package/dist/rich-text-editor-BM-LPpTh.js +0 -2902
- package/dist/rich-text-editor-BmsjY03B.js +0 -2949
- package/dist/rich-text-editor-BrdC5evx.js +0 -2244
- package/dist/rich-text-editor-CyggTOLQ.cjs +0 -2908
- package/dist/rich-text-editor-DbV-S7Fi.cjs +0 -2261
- package/dist/rich-text-editor-DoCkKhzk.cjs +0 -2919
- package/dist/rich-text-editor-GS2kpTAK.cjs +0 -2966
- package/dist/routes.d.ts +0 -10
- package/dist/select-Cmb8zF7w.cjs +0 -156
- package/dist/select-CprSNX0z.js +0 -139
- package/dist/select-DT7Zjn42.cjs +0 -162
- package/dist/select-En8DkoaQ.js +0 -145
- package/dist/sidebar-B3EYhli0.cjs +0 -800
- package/dist/sidebar-B9NR0lCe.cjs +0 -800
- package/dist/sidebar-BcJ6LxvX.cjs +0 -733
- package/dist/sidebar-BvF5I2Ue.cjs +0 -800
- package/dist/sidebar-C5B_LHek.cjs +0 -795
- package/dist/sidebar-CA6_ek3f.js +0 -801
- package/dist/sidebar-CRMiBtAi.js +0 -801
- package/dist/sidebar-CVUGHOS_.cjs +0 -756
- package/dist/sidebar-CZ2mWaMM.cjs +0 -800
- package/dist/sidebar-CmvwjnVb.js +0 -757
- package/dist/sidebar-CplprZpM.js +0 -801
- package/dist/sidebar-Dz7bd3zP.js +0 -796
- package/dist/sidebar-KIS0C2JH.js +0 -801
- package/dist/sidebar-OTO_up7Z.js +0 -801
- package/dist/sidebar-WoKvFWCN.js +0 -717
- package/dist/sidebar-zowjejT2.cjs +0 -800
- package/dist/skeleton-4zoHiFJ_.cjs +0 -83
- package/dist/skeleton-C4bHqUBf.js +0 -84
- package/dist/slider-C0JKA9k3.js +0 -56
- package/dist/slider-CPmwzm_3.cjs +0 -73
- package/dist/slider-DcJharR9.cjs +0 -73
- package/dist/slider-Pay3fka2.js +0 -56
- package/dist/sonner-DeUIj0Zg.cjs +0 -63
- package/dist/sonner-g9RIfi35.js +0 -47
- package/dist/tooltip-CNtsL5cB.cjs +0 -71
- package/dist/tooltip-CTyZCD8h.js +0 -55
- package/dist/tooltip-CwgSdy3h.cjs +0 -67
- package/dist/tooltip-D-OrYnKO.js +0 -51
- package/dist/use-audio-player-BJFV24XW.js +0 -188
- package/dist/use-audio-player-Bkh23vQ3.js +0 -177
- package/dist/use-audio-player-Dn1NR9xN.cjs +0 -176
- package/dist/use-audio-player-DyVYlOnR.cjs +0 -187
- package/dist/use-mobile-BB4M_4Ru.cjs +0 -47
- package/dist/use-mobile-CLu9nqGL.js +0 -31
- package/dist/use-mobile-CNwiBNxu.js +0 -33
- package/dist/use-mobile-Dlf74ufz.cjs +0 -49
- package/dist/xertica-assistant-B1IaHXnB.cjs +0 -1894
- package/dist/xertica-assistant-BMqdyRVi.js +0 -2082
- package/dist/xertica-assistant-Bj3vBCq_.cjs +0 -2081
- package/dist/xertica-assistant-CfBCo21g.js +0 -2148
- package/dist/xertica-assistant-DIM_Do1k.js +0 -1866
- package/dist/xertica-assistant-DPsESB6t.js +0 -1878
- package/dist/xertica-assistant-DrsRwla1.cjs +0 -2147
- package/dist/xertica-assistant-Qp3ydksa.cjs +0 -1882
- package/dist/xertica-assistant-gnCJdcZY.js +0 -1866
- package/dist/xertica-assistant-yyrR0JKl.cjs +0 -1882
- package/styles/xertica/app-overrides/scrollbar.css +0 -33
- package/dist/{XerticaXLogo-qBPhwK3g.cjs → LanguageSelector-1cINLJ23.cjs} +80 -80
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { screen, fireEvent, act, waitFor } from '@testing-library/react';
|
|
2
|
+
import { renderWithProviders as render } from '../../../test/render';
|
|
2
3
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
3
4
|
import { LoginPage } from './LoginPage';
|
|
4
5
|
import React from 'react';
|
|
@@ -1,243 +1,243 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Button } from '../../ui/button';
|
|
3
|
-
import { Input } from '../../ui/input';
|
|
4
|
-
import { Label } from '../../ui/label';
|
|
5
|
-
import { XerticaLogo } from '../../brand/xertica-logo';
|
|
6
|
-
import { ImageWithFallback } from '../../figma/ImageWithFallback';
|
|
7
|
-
import { LanguageSelector } from '../../brand/language-selector';
|
|
8
|
-
import { ArrowLeft, CheckCircle2, AlertCircle } from 'lucide-react';
|
|
9
|
-
import { useNavigate } from 'react-router-dom';
|
|
10
|
-
import { useTranslation } from 'react-i18next';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Reset Password Page component.
|
|
14
|
-
*
|
|
15
|
-
* @description
|
|
16
|
-
* A screen where users can set a new password after verifying their identity.
|
|
17
|
-
* Includes password strength validation logic and clear visual feedback for
|
|
18
|
-
* password requirements.
|
|
19
|
-
*
|
|
20
|
-
* @ai-rules
|
|
21
|
-
* 1. Validation: Includes a `checkPasswordStrength` helper that categorizes passwords as 'weak', 'medium', or 'strong'.
|
|
22
|
-
* 2. Feedback: Uses `CheckCircle2` icons to show real-time progress on password requirements (length, matching).
|
|
23
|
-
* 3. Navigation: Redirects to `/login` with a `resetSuccess` flag after a successful password update.
|
|
24
|
-
*/
|
|
25
|
-
export function ResetPasswordPage() {
|
|
26
|
-
const navigate = useNavigate();
|
|
27
|
-
const { t } = useTranslation();
|
|
28
|
-
const [password, setPassword] = useState('');
|
|
29
|
-
const [confirmPassword, setConfirmPassword] = useState('');
|
|
30
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
31
|
-
const [error, setError] = useState('');
|
|
32
|
-
const [passwordStrength, setPasswordStrength] = useState<'weak' | 'medium' | 'strong' | null>(
|
|
33
|
-
null
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// Password strength validation
|
|
37
|
-
const checkPasswordStrength = (pwd: string) => {
|
|
38
|
-
if (pwd.length === 0) {
|
|
39
|
-
setPasswordStrength(null);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (pwd.length < 6) {
|
|
44
|
-
setPasswordStrength('weak');
|
|
45
|
-
} else if (pwd.length < 10) {
|
|
46
|
-
setPasswordStrength('medium');
|
|
47
|
-
} else {
|
|
48
|
-
setPasswordStrength('strong');
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const handlePasswordChange = (value: string) => {
|
|
53
|
-
setPassword(value);
|
|
54
|
-
checkPasswordStrength(value);
|
|
55
|
-
setError('');
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const handleSubmit = async (e: React.FormEvent) => {
|
|
59
|
-
e.preventDefault();
|
|
60
|
-
setError('');
|
|
61
|
-
|
|
62
|
-
// Validations
|
|
63
|
-
if (password.length < 6) {
|
|
64
|
-
setError(t('resetPassword.errorMinLength'));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (password !== confirmPassword) {
|
|
69
|
-
setError(t('resetPassword.errorMismatch'));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
setIsLoading(true);
|
|
74
|
-
|
|
75
|
-
// Simulate password reset
|
|
76
|
-
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
77
|
-
|
|
78
|
-
// Redirect to login with success message
|
|
79
|
-
navigate('/login', { state: { resetSuccess: true } });
|
|
80
|
-
|
|
81
|
-
setIsLoading(false);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const getStrengthColor = () => {
|
|
85
|
-
switch (passwordStrength) {
|
|
86
|
-
case 'weak':
|
|
87
|
-
return 'text-destructive';
|
|
88
|
-
case 'medium':
|
|
89
|
-
return 'text-[var(--chart-3)]';
|
|
90
|
-
case 'strong':
|
|
91
|
-
return 'text-[var(--chart-2)]';
|
|
92
|
-
default:
|
|
93
|
-
return 'text-muted-foreground';
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const getStrengthText = () => {
|
|
98
|
-
switch (passwordStrength) {
|
|
99
|
-
case 'weak':
|
|
100
|
-
return t('resetPassword.strengthWeak');
|
|
101
|
-
case 'medium':
|
|
102
|
-
return t('resetPassword.strengthMedium');
|
|
103
|
-
case 'strong':
|
|
104
|
-
return t('resetPassword.strengthStrong');
|
|
105
|
-
default:
|
|
106
|
-
return '';
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<div className="h-screen w-full flex overflow-y-auto">
|
|
112
|
-
{/* Left side - Full background image */}
|
|
113
|
-
<div className="hidden lg:flex lg:flex-1 relative overflow-hidden">
|
|
114
|
-
{/* Background image filling all space */}
|
|
115
|
-
<ImageWithFallback
|
|
116
|
-
src="https://images.unsplash.com/photo-1555949963-aa79dcee981c?w=1200&h=800&fit=crop&auto=format"
|
|
117
|
-
alt={t('resetPassword.heroImageAlt')}
|
|
118
|
-
className="absolute inset-0 w-full h-full object-cover"
|
|
119
|
-
/>
|
|
120
|
-
|
|
121
|
-
{/* Gradient overlay */}
|
|
122
|
-
<div className="absolute inset-0 bg-[image:var(--gradient-diagonal)] opacity-80" />
|
|
123
|
-
</div>
|
|
124
|
-
|
|
125
|
-
{/* Right side - Form */}
|
|
126
|
-
<div className="flex-1 flex items-center justify-center px-4 sm:px-6 lg:px-8 lg:flex-none lg:w-1/2 relative bg-muted">
|
|
127
|
-
{/* Language selector in the top right corner */}
|
|
128
|
-
<div className="absolute top-4 right-4 z-20">
|
|
129
|
-
<LanguageSelector variant="minimal" showIcon={false} />
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
{/* Mobile background gradient */}
|
|
133
|
-
<div className="absolute inset-0 lg:hidden bg-[image:var(--gradient-diagonal)] opacity-10 dark:opacity-5" />
|
|
134
|
-
|
|
135
|
-
<div className="w-full max-w-sm space-y-6 relative z-10">
|
|
136
|
-
{/* Botão voltar */}
|
|
137
|
-
<button
|
|
138
|
-
onClick={() => navigate('/login')}
|
|
139
|
-
className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors"
|
|
140
|
-
>
|
|
141
|
-
<ArrowLeft className="w-4 h-4" />
|
|
142
|
-
<span className="text-small">{t('resetPassword.backToLogin')}</span>
|
|
143
|
-
</button>
|
|
144
|
-
|
|
145
|
-
{/* Header do formulário */}
|
|
146
|
-
<div className="text-center">
|
|
147
|
-
<div className="flex items-center justify-center mb-4">
|
|
148
|
-
<XerticaLogo
|
|
149
|
-
className="h-12 w-auto text-primary dark:text-foreground"
|
|
150
|
-
variant="theme"
|
|
151
|
-
/>
|
|
152
|
-
</div>
|
|
153
|
-
<h2 className="text-sm text-muted-foreground">{t('resetPassword.heading')}</h2>
|
|
154
|
-
<p className="mt-2 text-muted-foreground">{t('resetPassword.subheading')}</p>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
{/* Form */}
|
|
158
|
-
<form className="space-y-6" onSubmit={handleSubmit}>
|
|
159
|
-
<div className="space-y-2">
|
|
160
|
-
<Label htmlFor="password">{t('resetPassword.newPasswordLabel')}</Label>
|
|
161
|
-
<Input
|
|
162
|
-
id="password"
|
|
163
|
-
name="password"
|
|
164
|
-
type="password"
|
|
165
|
-
required
|
|
166
|
-
className="w-full"
|
|
167
|
-
placeholder="••••••••"
|
|
168
|
-
value={password}
|
|
169
|
-
onChange={e => handlePasswordChange(e.target.value)}
|
|
170
|
-
/>
|
|
171
|
-
{passwordStrength && (
|
|
172
|
-
<div className="flex items-center gap-2">
|
|
173
|
-
<div className="flex-1 h-1 bg-muted rounded-full overflow-hidden">
|
|
174
|
-
<div
|
|
175
|
-
className={`h-full transition-all duration-300 ${
|
|
176
|
-
passwordStrength === 'weak'
|
|
177
|
-
? 'w-1/3 bg-destructive'
|
|
178
|
-
: passwordStrength === 'medium'
|
|
179
|
-
? 'w-2/3 bg-[var(--chart-3)]'
|
|
180
|
-
: 'w-full bg-[var(--chart-2)]'
|
|
181
|
-
}`}
|
|
182
|
-
/>
|
|
183
|
-
</div>
|
|
184
|
-
<span className={`text-small ${getStrengthColor()}`}>{getStrengthText()}</span>
|
|
185
|
-
</div>
|
|
186
|
-
)}
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
<div className="space-y-2">
|
|
190
|
-
<Label htmlFor="confirmPassword">{t('resetPassword.confirmPasswordLabel')}</Label>
|
|
191
|
-
<Input
|
|
192
|
-
id="confirmPassword"
|
|
193
|
-
name="confirmPassword"
|
|
194
|
-
type="password"
|
|
195
|
-
required
|
|
196
|
-
className="w-full"
|
|
197
|
-
placeholder="••••••••"
|
|
198
|
-
value={confirmPassword}
|
|
199
|
-
onChange={e => {
|
|
200
|
-
setConfirmPassword(e.target.value);
|
|
201
|
-
setError('');
|
|
202
|
-
}}
|
|
203
|
-
/>
|
|
204
|
-
</div>
|
|
205
|
-
|
|
206
|
-
<div className="bg-accent rounded-[var(--radius)] p-4 space-y-2">
|
|
207
|
-
<p className="text-sm">{t('resetPassword.requirements')}</p>
|
|
208
|
-
<div className="space-y-1">
|
|
209
|
-
<div className="flex items-center gap-2">
|
|
210
|
-
<CheckCircle2
|
|
211
|
-
className={`w-4 h-4 ${password.length >= 6 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
212
|
-
/>
|
|
213
|
-
<span className="text-sm text-muted-foreground">
|
|
214
|
-
{t('resetPassword.requirementMinChars')}
|
|
215
|
-
</span>
|
|
216
|
-
</div>
|
|
217
|
-
<div className="flex items-center gap-2">
|
|
218
|
-
<CheckCircle2
|
|
219
|
-
className={`w-4 h-4 ${password === confirmPassword && password.length > 0 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
220
|
-
/>
|
|
221
|
-
<span className="text-sm text-muted-foreground">
|
|
222
|
-
{t('resetPassword.requirementMatch')}
|
|
223
|
-
</span>
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
</div>
|
|
227
|
-
|
|
228
|
-
{error && (
|
|
229
|
-
<div className="flex items-center gap-2 text-destructive bg-destructive/10 rounded-[var(--radius)] p-3">
|
|
230
|
-
<AlertCircle className="w-4 h-4 flex-shrink-0" />
|
|
231
|
-
<span className="text-sm">{error}</span>
|
|
232
|
-
</div>
|
|
233
|
-
)}
|
|
234
|
-
|
|
235
|
-
<Button type="submit" className="w-full" disabled={isLoading}>
|
|
236
|
-
{isLoading ? t('resetPassword.submitting') : t('resetPassword.submit')}
|
|
237
|
-
</Button>
|
|
238
|
-
</form>
|
|
239
|
-
</div>
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
);
|
|
243
|
-
}
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Button } from '../../ui/button';
|
|
3
|
+
import { Input } from '../../ui/input';
|
|
4
|
+
import { Label } from '../../ui/label';
|
|
5
|
+
import { XerticaLogo } from '../../brand/xertica-logo';
|
|
6
|
+
import { ImageWithFallback } from '../../figma/ImageWithFallback';
|
|
7
|
+
import { LanguageSelector } from '../../brand/language-selector';
|
|
8
|
+
import { ArrowLeft, CheckCircle2, AlertCircle } from 'lucide-react';
|
|
9
|
+
import { useNavigate } from 'react-router-dom';
|
|
10
|
+
import { useTranslation } from 'react-i18next';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Reset Password Page component.
|
|
14
|
+
*
|
|
15
|
+
* @description
|
|
16
|
+
* A screen where users can set a new password after verifying their identity.
|
|
17
|
+
* Includes password strength validation logic and clear visual feedback for
|
|
18
|
+
* password requirements.
|
|
19
|
+
*
|
|
20
|
+
* @ai-rules
|
|
21
|
+
* 1. Validation: Includes a `checkPasswordStrength` helper that categorizes passwords as 'weak', 'medium', or 'strong'.
|
|
22
|
+
* 2. Feedback: Uses `CheckCircle2` icons to show real-time progress on password requirements (length, matching).
|
|
23
|
+
* 3. Navigation: Redirects to `/login` with a `resetSuccess` flag after a successful password update.
|
|
24
|
+
*/
|
|
25
|
+
export function ResetPasswordPage() {
|
|
26
|
+
const navigate = useNavigate();
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
const [password, setPassword] = useState('');
|
|
29
|
+
const [confirmPassword, setConfirmPassword] = useState('');
|
|
30
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
31
|
+
const [error, setError] = useState('');
|
|
32
|
+
const [passwordStrength, setPasswordStrength] = useState<'weak' | 'medium' | 'strong' | null>(
|
|
33
|
+
null
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Password strength validation
|
|
37
|
+
const checkPasswordStrength = (pwd: string) => {
|
|
38
|
+
if (pwd.length === 0) {
|
|
39
|
+
setPasswordStrength(null);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (pwd.length < 6) {
|
|
44
|
+
setPasswordStrength('weak');
|
|
45
|
+
} else if (pwd.length < 10) {
|
|
46
|
+
setPasswordStrength('medium');
|
|
47
|
+
} else {
|
|
48
|
+
setPasswordStrength('strong');
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handlePasswordChange = (value: string) => {
|
|
53
|
+
setPassword(value);
|
|
54
|
+
checkPasswordStrength(value);
|
|
55
|
+
setError('');
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
setError('');
|
|
61
|
+
|
|
62
|
+
// Validations
|
|
63
|
+
if (password.length < 6) {
|
|
64
|
+
setError(t('resetPassword.errorMinLength'));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (password !== confirmPassword) {
|
|
69
|
+
setError(t('resetPassword.errorMismatch'));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
setIsLoading(true);
|
|
74
|
+
|
|
75
|
+
// Simulate password reset
|
|
76
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
77
|
+
|
|
78
|
+
// Redirect to login with success message
|
|
79
|
+
navigate('/login', { state: { resetSuccess: true } });
|
|
80
|
+
|
|
81
|
+
setIsLoading(false);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const getStrengthColor = () => {
|
|
85
|
+
switch (passwordStrength) {
|
|
86
|
+
case 'weak':
|
|
87
|
+
return 'text-destructive';
|
|
88
|
+
case 'medium':
|
|
89
|
+
return 'text-[var(--chart-3)]';
|
|
90
|
+
case 'strong':
|
|
91
|
+
return 'text-[var(--chart-2)]';
|
|
92
|
+
default:
|
|
93
|
+
return 'text-muted-foreground';
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const getStrengthText = () => {
|
|
98
|
+
switch (passwordStrength) {
|
|
99
|
+
case 'weak':
|
|
100
|
+
return t('resetPassword.strengthWeak');
|
|
101
|
+
case 'medium':
|
|
102
|
+
return t('resetPassword.strengthMedium');
|
|
103
|
+
case 'strong':
|
|
104
|
+
return t('resetPassword.strengthStrong');
|
|
105
|
+
default:
|
|
106
|
+
return '';
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div className="h-screen w-full flex overflow-y-auto">
|
|
112
|
+
{/* Left side - Full background image */}
|
|
113
|
+
<div className="hidden lg:flex lg:flex-1 relative overflow-hidden">
|
|
114
|
+
{/* Background image filling all space */}
|
|
115
|
+
<ImageWithFallback
|
|
116
|
+
src="https://images.unsplash.com/photo-1555949963-aa79dcee981c?w=1200&h=800&fit=crop&auto=format"
|
|
117
|
+
alt={t('resetPassword.heroImageAlt')}
|
|
118
|
+
className="absolute inset-0 w-full h-full object-cover"
|
|
119
|
+
/>
|
|
120
|
+
|
|
121
|
+
{/* Gradient overlay */}
|
|
122
|
+
<div className="absolute inset-0 bg-[image:var(--gradient-diagonal)] opacity-80" />
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{/* Right side - Form */}
|
|
126
|
+
<div className="flex-1 flex items-center justify-center px-4 sm:px-6 lg:px-8 lg:flex-none lg:w-1/2 relative bg-muted">
|
|
127
|
+
{/* Language selector in the top right corner */}
|
|
128
|
+
<div className="absolute top-4 right-4 z-20">
|
|
129
|
+
<LanguageSelector variant="minimal" showIcon={false} />
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
{/* Mobile background gradient */}
|
|
133
|
+
<div className="absolute inset-0 lg:hidden bg-[image:var(--gradient-diagonal)] opacity-10 dark:opacity-5" />
|
|
134
|
+
|
|
135
|
+
<div className="w-full max-w-sm space-y-6 relative z-10">
|
|
136
|
+
{/* Botão voltar */}
|
|
137
|
+
<button
|
|
138
|
+
onClick={() => navigate('/login')}
|
|
139
|
+
className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors"
|
|
140
|
+
>
|
|
141
|
+
<ArrowLeft className="w-4 h-4" />
|
|
142
|
+
<span className="text-small">{t('resetPassword.backToLogin')}</span>
|
|
143
|
+
</button>
|
|
144
|
+
|
|
145
|
+
{/* Header do formulário */}
|
|
146
|
+
<div className="text-center">
|
|
147
|
+
<div className="flex items-center justify-center mb-4">
|
|
148
|
+
<XerticaLogo
|
|
149
|
+
className="h-12 w-auto text-primary dark:text-foreground"
|
|
150
|
+
variant="theme"
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
<h2 className="text-sm text-muted-foreground">{t('resetPassword.heading')}</h2>
|
|
154
|
+
<p className="mt-2 text-muted-foreground">{t('resetPassword.subheading')}</p>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
{/* Form */}
|
|
158
|
+
<form className="space-y-6" onSubmit={handleSubmit}>
|
|
159
|
+
<div className="space-y-2">
|
|
160
|
+
<Label htmlFor="password">{t('resetPassword.newPasswordLabel')}</Label>
|
|
161
|
+
<Input
|
|
162
|
+
id="password"
|
|
163
|
+
name="password"
|
|
164
|
+
type="password"
|
|
165
|
+
required
|
|
166
|
+
className="w-full"
|
|
167
|
+
placeholder="••••••••"
|
|
168
|
+
value={password}
|
|
169
|
+
onChange={e => handlePasswordChange(e.target.value)}
|
|
170
|
+
/>
|
|
171
|
+
{passwordStrength && (
|
|
172
|
+
<div className="flex items-center gap-2">
|
|
173
|
+
<div className="flex-1 h-1 bg-muted rounded-full overflow-hidden">
|
|
174
|
+
<div
|
|
175
|
+
className={`h-full transition-all duration-300 ${
|
|
176
|
+
passwordStrength === 'weak'
|
|
177
|
+
? 'w-1/3 bg-destructive'
|
|
178
|
+
: passwordStrength === 'medium'
|
|
179
|
+
? 'w-2/3 bg-[var(--chart-3)]'
|
|
180
|
+
: 'w-full bg-[var(--chart-2)]'
|
|
181
|
+
}`}
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
<span className={`text-small ${getStrengthColor()}`}>{getStrengthText()}</span>
|
|
185
|
+
</div>
|
|
186
|
+
)}
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
<div className="space-y-2">
|
|
190
|
+
<Label htmlFor="confirmPassword">{t('resetPassword.confirmPasswordLabel')}</Label>
|
|
191
|
+
<Input
|
|
192
|
+
id="confirmPassword"
|
|
193
|
+
name="confirmPassword"
|
|
194
|
+
type="password"
|
|
195
|
+
required
|
|
196
|
+
className="w-full"
|
|
197
|
+
placeholder="••••••••"
|
|
198
|
+
value={confirmPassword}
|
|
199
|
+
onChange={e => {
|
|
200
|
+
setConfirmPassword(e.target.value);
|
|
201
|
+
setError('');
|
|
202
|
+
}}
|
|
203
|
+
/>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<div className="bg-accent rounded-[var(--radius)] p-4 space-y-2">
|
|
207
|
+
<p className="text-sm">{t('resetPassword.requirements')}</p>
|
|
208
|
+
<div className="space-y-1">
|
|
209
|
+
<div className="flex items-center gap-2">
|
|
210
|
+
<CheckCircle2
|
|
211
|
+
className={`w-4 h-4 ${password.length >= 6 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
212
|
+
/>
|
|
213
|
+
<span className="text-sm text-muted-foreground">
|
|
214
|
+
{t('resetPassword.requirementMinChars')}
|
|
215
|
+
</span>
|
|
216
|
+
</div>
|
|
217
|
+
<div className="flex items-center gap-2">
|
|
218
|
+
<CheckCircle2
|
|
219
|
+
className={`w-4 h-4 ${password === confirmPassword && password.length > 0 ? 'text-[var(--chart-2)]' : 'text-muted-foreground'}`}
|
|
220
|
+
/>
|
|
221
|
+
<span className="text-sm text-muted-foreground">
|
|
222
|
+
{t('resetPassword.requirementMatch')}
|
|
223
|
+
</span>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
{error && (
|
|
229
|
+
<div className="flex items-center gap-2 text-destructive bg-destructive/10 rounded-[var(--radius)] p-3">
|
|
230
|
+
<AlertCircle className="w-4 h-4 flex-shrink-0" />
|
|
231
|
+
<span className="text-sm">{error}</span>
|
|
232
|
+
</div>
|
|
233
|
+
)}
|
|
234
|
+
|
|
235
|
+
<Button type="submit" className="w-full" disabled={isLoading}>
|
|
236
|
+
{isLoading ? t('resetPassword.submitting') : t('resetPassword.submit')}
|
|
237
|
+
</Button>
|
|
238
|
+
</form>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
import { Meta, Title, Subtitle } from '@storybook/addon-docs/blocks';
|
|
2
|
-
|
|
3
|
-
<Meta title="Pages/ResetPasswordPage" />
|
|
4
|
-
|
|
5
|
-
<Title>ResetPasswordPage</Title>
|
|
6
|
-
<Subtitle>Full-page new-password form with a real-time strength meter.</Subtitle>
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Overview
|
|
11
|
-
|
|
12
|
-
`ResetPasswordPage` renders a centered password-reset form. It includes:
|
|
13
|
-
|
|
14
|
-
- A password field with live strength feedback (`weak` / `medium` / `strong`).
|
|
15
|
-
- A confirm-password field with match validation.
|
|
16
|
-
- On success, navigates to `/login` with `{ state: { resetSuccess: true } }` so that `LoginPage` can show a success banner.
|
|
17
|
-
|
|
18
|
-
This component requires React Router v6+.
|
|
19
|
-
|
|
20
|
-
```tsx
|
|
21
|
-
import { ResetPasswordPage } from 'xertica-ui';
|
|
22
|
-
|
|
23
|
-
// In your router config:
|
|
24
|
-
{ path: '/reset-password', element: <ResetPasswordPage /> }
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Navigation Flow
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
/reset-password ──[submit valid password]──▶ /login (state: { resetSuccess: true })
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## Password Strength Levels
|
|
38
|
-
|
|
39
|
-
The strength meter is based purely on length:
|
|
40
|
-
|
|
41
|
-
| Level | Criteria |
|
|
42
|
-
|---|---|
|
|
43
|
-
| `weak` | Fewer than 6 characters |
|
|
44
|
-
| `medium` | 6–9 characters |
|
|
45
|
-
| `strong` | 10 or more characters |
|
|
46
|
-
|
|
47
|
-
The meter is visual-only. Enforce your own policy server-side.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Props
|
|
52
|
-
|
|
53
|
-
This component accepts no props — it is a self-contained page.
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## AI Best Practices
|
|
58
|
-
|
|
59
|
-
> [!IMPORTANT]
|
|
60
|
-
> - **Router requirement** — Must be inside a React Router `<BrowserRouter>`. `useNavigate` is used internally.
|
|
61
|
-
> - **Route pairing** — Register `/login` so the post-reset redirect lands correctly. The `LoginPage` should read `location.state?.resetSuccess` to show a confirmation message.
|
|
62
|
-
> - **Token handling** — The component does not receive or validate a reset token. Pass the token via URL params (e.g., `/reset-password?token=abc`) and read it with `useSearchParams` in a wrapper component that calls your API before rendering this page.
|
|
63
|
-
> - **Strength meter** — The meter is visual-only for UX feedback. Always enforce password policy server-side as well.
|
|
1
|
+
import { Meta, Title, Subtitle } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Pages/ResetPasswordPage" />
|
|
4
|
+
|
|
5
|
+
<Title>ResetPasswordPage</Title>
|
|
6
|
+
<Subtitle>Full-page new-password form with a real-time strength meter.</Subtitle>
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
`ResetPasswordPage` renders a centered password-reset form. It includes:
|
|
13
|
+
|
|
14
|
+
- A password field with live strength feedback (`weak` / `medium` / `strong`).
|
|
15
|
+
- A confirm-password field with match validation.
|
|
16
|
+
- On success, navigates to `/login` with `{ state: { resetSuccess: true } }` so that `LoginPage` can show a success banner.
|
|
17
|
+
|
|
18
|
+
This component requires React Router v6+.
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { ResetPasswordPage } from 'xertica-ui';
|
|
22
|
+
|
|
23
|
+
// In your router config:
|
|
24
|
+
{ path: '/reset-password', element: <ResetPasswordPage /> }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Navigation Flow
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
/reset-password ──[submit valid password]──▶ /login (state: { resetSuccess: true })
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Password Strength Levels
|
|
38
|
+
|
|
39
|
+
The strength meter is based purely on length:
|
|
40
|
+
|
|
41
|
+
| Level | Criteria |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `weak` | Fewer than 6 characters |
|
|
44
|
+
| `medium` | 6–9 characters |
|
|
45
|
+
| `strong` | 10 or more characters |
|
|
46
|
+
|
|
47
|
+
The meter is visual-only. Enforce your own policy server-side.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Props
|
|
52
|
+
|
|
53
|
+
This component accepts no props — it is a self-contained page.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## AI Best Practices
|
|
58
|
+
|
|
59
|
+
> [!IMPORTANT]
|
|
60
|
+
> - **Router requirement** — Must be inside a React Router `<BrowserRouter>`. `useNavigate` is used internally.
|
|
61
|
+
> - **Route pairing** — Register `/login` so the post-reset redirect lands correctly. The `LoginPage` should read `location.state?.resetSuccess` to show a confirmation message.
|
|
62
|
+
> - **Token handling** — The component does not receive or validate a reset token. Pass the token via URL params (e.g., `/reset-password?token=abc`) and read it with `useSearchParams` in a wrapper component that calls your API before rendering this page.
|
|
63
|
+
> - **Strength meter** — The meter is visual-only for UX feedback. Always enforce password policy server-side as well.
|
|
@@ -47,7 +47,6 @@ import {
|
|
|
47
47
|
} from 'lucide-react';
|
|
48
48
|
import { Slider } from '../../ui/slider';
|
|
49
49
|
import { toast } from 'sonner';
|
|
50
|
-
import { ScrollArea } from '../../ui/scroll-area';
|
|
51
50
|
import { ThemeToggle } from '../../brand/theme-toggle';
|
|
52
51
|
import { LanguageSelector } from '../../brand/language-selector';
|
|
53
52
|
import { MapShowcase } from '../../examples/MapShowcase';
|
|
@@ -154,7 +153,7 @@ export function TemplateContent() {
|
|
|
154
153
|
|
|
155
154
|
{/* Content area */}
|
|
156
155
|
<main className="flex-1 overflow-hidden bg-muted">
|
|
157
|
-
<
|
|
156
|
+
<div className="h-full" style={{ overflowY: 'auto', overflowX: 'hidden' }}>
|
|
158
157
|
<div className="p-5 sm:p-4 md:p-6">
|
|
159
158
|
<div className="max-w-6xl mx-auto space-y-8">
|
|
160
159
|
{/* Page header */}
|
|
@@ -1347,7 +1346,7 @@ export function TemplateContent() {
|
|
|
1347
1346
|
</Card>
|
|
1348
1347
|
</div>
|
|
1349
1348
|
</div>
|
|
1350
|
-
</
|
|
1349
|
+
</div>
|
|
1351
1350
|
</main>
|
|
1352
1351
|
</div>
|
|
1353
1352
|
);
|