@plumile/backoffice-react 0.1.143 → 0.1.145

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.
Files changed (230) hide show
  1. package/lib/esm/auth/AuthRefreshNotice.js.map +1 -1
  2. package/lib/esm/auth/TotpQrCode.js.map +1 -1
  3. package/lib/esm/auth/authRefreshNotice.css.js +1 -1
  4. package/lib/esm/auth/login/AuthPanel.js.map +1 -1
  5. package/lib/esm/auth/login/EmailCapturePanel.js.map +1 -1
  6. package/lib/esm/auth/login/LoginFlow.js.map +1 -1
  7. package/lib/esm/auth/login/MethodChooser.js.map +1 -1
  8. package/lib/esm/auth/login/MfaChallengeForm.js.map +1 -1
  9. package/lib/esm/auth/login/OidcButtons.js.map +1 -1
  10. package/lib/esm/auth/login/PasskeyLoginForm.js.map +1 -1
  11. package/lib/esm/auth/login/PasswordLoginPanel.js.map +1 -1
  12. package/lib/esm/auth/login/loginPage.css.js +1 -1
  13. package/lib/esm/auth/login/loginPage.css.js.map +1 -1
  14. package/lib/esm/auth/login/synchronizeAuthStatusQuery.js.map +1 -1
  15. package/lib/esm/auth/pages/AcceptInvitationScreen.js.map +1 -1
  16. package/lib/esm/auth/pages/PasswordResetCompleteScreen.js.map +1 -1
  17. package/lib/esm/auth/pages/PasswordResetRequestScreen.js.map +1 -1
  18. package/lib/esm/auth/pages/VerifyEmailScreen.js.map +1 -1
  19. package/lib/esm/components/backoffice/actions/BackofficeEntityActionFormDialog.js +14 -14
  20. package/lib/esm/components/backoffice/actions/BackofficeEntityActionFormDialog.js.map +1 -1
  21. package/lib/esm/components/backoffice/actions/LazyBackofficeEntityActionFormDialog.js.map +1 -1
  22. package/lib/esm/components/backoffice/actions/backofficeEntityActionFormDialog.css.js +1 -1
  23. package/lib/esm/components/backoffice/actions/toastViewAction.js.map +1 -1
  24. package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js +1 -1
  25. package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js.map +1 -1
  26. package/lib/esm/components/backoffice/billing/backofficeBillingUsageChart.css.js +1 -1
  27. package/lib/esm/components/backoffice/columns/buildDataTableColumns.js.map +1 -1
  28. package/lib/esm/components/backoffice/detail/BackofficeDetailBadgeRow.js.map +1 -1
  29. package/lib/esm/components/backoffice/detail/BackofficeDetailErrorList.js.map +1 -1
  30. package/lib/esm/components/backoffice/detail/BackofficeDetailFlagTag.js.map +1 -1
  31. package/lib/esm/components/backoffice/detail/BackofficeDetailRelationLink.js.map +1 -1
  32. package/lib/esm/components/backoffice/detail/BackofficeDetailRelationList.js.map +1 -1
  33. package/lib/esm/components/backoffice/detail/BackofficeDetailRelationListBlock.js.map +1 -1
  34. package/lib/esm/components/backoffice/detail/BackofficeDetailTaggedValue.js.map +1 -1
  35. package/lib/esm/components/backoffice/detail/BackofficeEntitySummaryHeader.js +6 -6
  36. package/lib/esm/components/backoffice/detail/BackofficeEntitySummaryHeader.js.map +1 -1
  37. package/lib/esm/components/backoffice/detail/BackofficeEnumLabel.js.map +1 -1
  38. package/lib/esm/components/backoffice/detail/BackofficeLifecycleTimelineSection.js.map +1 -1
  39. package/lib/esm/components/backoffice/detail/BackofficeReferenceValue.js.map +1 -1
  40. package/lib/esm/components/backoffice/detail/BackofficeRelationsSummaryGrid.js +1 -1
  41. package/lib/esm/components/backoffice/detail/BackofficeRelationsSummaryGrid.js.map +1 -1
  42. package/lib/esm/components/backoffice/detail/BackofficeStatusGroup.js.map +1 -1
  43. package/lib/esm/components/backoffice/detail/BackofficeStatusMetaBadge.js.map +1 -1
  44. package/lib/esm/components/backoffice/detail/BackofficeTokenUsageBreakdown.js.map +1 -1
  45. package/lib/esm/components/backoffice/detail/BackofficeUsageCostBreakdown.js +13 -13
  46. package/lib/esm/components/backoffice/detail/BackofficeUsageCostBreakdown.js.map +1 -1
  47. package/lib/esm/components/backoffice/detail/backofficeDetailBadgeRow.css.js +1 -1
  48. package/lib/esm/components/backoffice/detail/backofficeDetailErrorList.css.js +1 -1
  49. package/lib/esm/components/backoffice/detail/backofficeDetailLayout.css.js +1 -1
  50. package/lib/esm/components/backoffice/detail/backofficeDetailRelationLink.css.js +2 -1
  51. package/lib/esm/components/backoffice/detail/backofficeDetailRelationList.css.js +1 -1
  52. package/lib/esm/components/backoffice/detail/backofficeEntitySummaryHeader.css.js +1 -1
  53. package/lib/esm/components/backoffice/detail/backofficeRelationsSummaryGrid.css.js +1 -1
  54. package/lib/esm/components/backoffice/detail/backofficeUsageCostBreakdown.css.js +1 -1
  55. package/lib/esm/components/backoffice/detail/createBackofficeEntityLinkProps.js.map +1 -1
  56. package/lib/esm/components/backoffice/detail/detailPayloadUtils.js.map +1 -1
  57. package/lib/esm/components/backoffice/errors/BackofficeErrorBoundary.js.map +1 -1
  58. package/lib/esm/components/backoffice/filters/BackofficeFilterAction.js.map +1 -1
  59. package/lib/esm/components/backoffice/filters/DeferredFilterSearchInput.js.map +1 -1
  60. package/lib/esm/components/backoffice/filters/EntityFilterValue.js.map +1 -1
  61. package/lib/esm/components/backoffice/filters/EntityIdFilterField.js +1 -1
  62. package/lib/esm/components/backoffice/filters/EntityIdFilterField.js.map +1 -1
  63. package/lib/esm/components/backoffice/filters/backofficeFilterAction.css.js +1 -1
  64. package/lib/esm/components/backoffice/filters/backofficeFilterAction.css.js.map +1 -1
  65. package/lib/esm/components/backoffice/filters/deferredFilterSearchInput.css.js +1 -1
  66. package/lib/esm/components/backoffice/filters/entityIdFilterField.css.js +1 -1
  67. package/lib/esm/components/backoffice/hub/BackofficeHubTemplate.js +5 -5
  68. package/lib/esm/components/backoffice/hub/BackofficeHubTemplate.js.map +1 -1
  69. package/lib/esm/components/backoffice/hub/backofficeHubTemplate.css.js +1 -1
  70. package/lib/esm/components/backoffice/layout/BackofficePermissionsContext.js.map +1 -1
  71. package/lib/esm/components/backoffice/layout/backofficeSidebarActions.css.js +1 -1
  72. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.js.map +1 -1
  73. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.js +2 -2
  74. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.js.map +1 -1
  75. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarPortal.js.map +1 -1
  76. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js.map +1 -1
  77. package/lib/esm/components/backoffice/layout/breadcrumb/assertValidBreadcrumb.js.map +1 -1
  78. package/lib/esm/components/backoffice/layout/breadcrumb/backofficeTopbarBreadcrumb.css.js +1 -2
  79. package/lib/esm/components/backoffice/layout/breadcrumb/buildBreadcrumbs.js.map +1 -1
  80. package/lib/esm/components/backoffice/layout/buildSidebarSections.js.map +1 -1
  81. package/lib/esm/components/backoffice/layout/mapViewerToSidebarProfileView.js.map +1 -1
  82. package/lib/esm/components/backoffice/layout/sidebarUtils.js.map +1 -1
  83. package/lib/esm/components/backoffice/links/BackofficeInlineLink.js.map +1 -1
  84. package/lib/esm/components/backoffice/links/BackofficeLink.js.map +1 -1
  85. package/lib/esm/components/backoffice/links/BackofficeLinkContent.js +1 -1
  86. package/lib/esm/components/backoffice/links/BackofficeLinkContent.js.map +1 -1
  87. package/lib/esm/components/backoffice/links/BackofficeLinkLabel.js.map +1 -1
  88. package/lib/esm/components/backoffice/links/backofficeLink.css.js +1 -1
  89. package/lib/esm/components/backoffice/links/resolveBackofficeLink.js.map +1 -1
  90. package/lib/esm/components/backoffice/links/resolveBackofficeTargetIcon.js.map +1 -1
  91. package/lib/esm/components/backoffice/links/useBackofficeLink.js.map +1 -1
  92. package/lib/esm/components/backoffice/list/RowFlagsCell.css.js +1 -1
  93. package/lib/esm/components/backoffice/list/RowFlagsCell.js.map +1 -1
  94. package/lib/esm/components/backoffice/overview/BackofficeOverviewLayout.js.map +1 -1
  95. package/lib/esm/components/backoffice/overview/backofficeOverviewLayout.css.js +1 -1
  96. package/lib/esm/components/backoffice/overview/backofficeOverviewLayout.css.js.map +1 -1
  97. package/lib/esm/components/backoffice/pickers/EntityIdPickerDialog.js.map +1 -1
  98. package/lib/esm/components/backoffice/pickers/entityIdPickerDialog.css.js +1 -1
  99. package/lib/esm/components/backoffice/refs/BackofficeEntityIdRef.js.map +1 -1
  100. package/lib/esm/components/backoffice/refs/BackofficeEntityLink.js.map +1 -1
  101. package/lib/esm/components/backoffice/refs/BackofficeRelatedCountLink.js.map +1 -1
  102. package/lib/esm/components/backoffice/refs/backofficeEntityIdRef.css.js +1 -1
  103. package/lib/esm/components/backoffice/refs/backofficeRelatedCountLink.css.js +1 -1
  104. package/lib/esm/components/backoffice/routing/BackofficeContentBoundary.js.map +1 -1
  105. package/lib/esm/components/backoffice/routing/BackofficeContentError.js.map +1 -1
  106. package/lib/esm/components/backoffice/routing/BackofficeContentFallback.js.map +1 -1
  107. package/lib/esm/components/backoffice/routing/BackofficeRouteFallback.js.map +1 -1
  108. package/lib/esm/components/backoffice/routing/BackofficeRoutePendingBar.js.map +1 -1
  109. package/lib/esm/components/backoffice/routing/backofficeContentBoundary.css.js +1 -1
  110. package/lib/esm/components/backoffice/routing/backofficeContentError.css.js +1 -1
  111. package/lib/esm/components/backoffice/routing/backofficeContentFallback.css.js +1 -1
  112. package/lib/esm/components/backoffice/routing/backofficeRouteFallback.css.js +1 -1
  113. package/lib/esm/components/backoffice/routing/backofficeRoutePendingBar.css.js +1 -1
  114. package/lib/esm/components/backoffice/routing/backofficeRoutePendingBar.css.js.map +1 -1
  115. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityDetailScaffold.js.map +1 -1
  116. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
  117. package/lib/esm/components/backoffice/scaffolds/BackofficeListFilterContext.js.map +1 -1
  118. package/lib/esm/components/backoffice/scaffolds/BackofficeTabbedDetailShell.js.map +1 -1
  119. package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js +1 -1
  120. package/lib/esm/components/backoffice/scaffolds/backofficeTabbedDetailShell.css.js +1 -1
  121. package/lib/esm/components/backoffice/shared/BackofficeFilterableCell.js.map +1 -1
  122. package/lib/esm/components/backoffice/shared/BackofficeFormattedCurrency.js.map +1 -1
  123. package/lib/esm/components/backoffice/shared/BackofficeFormattedNumber.js.map +1 -1
  124. package/lib/esm/components/backoffice/shared/BackofficeInlineFilterRow.js.map +1 -1
  125. package/lib/esm/components/backoffice/shared/backofficeFilterableCell.css.js +5 -5
  126. package/lib/esm/components/backoffice/shared/backofficeFilterableCell.css.js.map +1 -1
  127. package/lib/esm/components/backoffice/shared/backofficeInlineFilterRow.css.js +1 -1
  128. package/lib/esm/components/backoffice/tools/BackofficeToolsDocPanel.js +1 -1
  129. package/lib/esm/components/backoffice/tools/BackofficeToolsDocPanel.js.map +1 -1
  130. package/lib/esm/components/backoffice/tools/BackofficeToolsErrorFallback.js.map +1 -1
  131. package/lib/esm/components/backoffice/tools/BackofficeToolsJsonForm.js.map +1 -1
  132. package/lib/esm/components/backoffice/tools/BackofficeToolsQueryBoundary.js.map +1 -1
  133. package/lib/esm/components/backoffice/tools/backofficeToolsDocPanel.css.js +1 -1
  134. package/lib/esm/components/backoffice/tools/backofficeToolsDocPanel.css.js.map +1 -1
  135. package/lib/esm/components/backoffice/tools/backofficeToolsForm.css.js +1 -1
  136. package/lib/esm/components/backoffice/tools/backofficeToolsJsonForm.css.js +1 -1
  137. package/lib/esm/components/backoffice/tools/parseToolJson.js.map +1 -1
  138. package/lib/esm/filters/filterHelpers.js.map +1 -1
  139. package/lib/esm/hooks/useAuth.js.map +1 -1
  140. package/lib/esm/hooks/useBackofficeAuth.js.map +1 -1
  141. package/lib/esm/hooks/useBackofficeInfiniteScrollSentinel.js.map +1 -1
  142. package/lib/esm/hooks/useBackofficeListRefetch.js.map +1 -1
  143. package/lib/esm/hooks/useBackofficeListUrlState.js.map +1 -1
  144. package/lib/esm/hooks/useBackofficeLoadMore.js.map +1 -1
  145. package/lib/esm/hooks/useBackofficeSessionAuth.js.map +1 -1
  146. package/lib/esm/hooks/useBackofficeSidebarPins.js.map +1 -1
  147. package/lib/esm/hooks/useConditionalSubscription.js.map +1 -1
  148. package/lib/esm/hooks/useCopyToClipboard.js.map +1 -1
  149. package/lib/esm/hooks/useInfiniteConnection.js.map +1 -1
  150. package/lib/esm/hooks/useRefetchNeededReload.js.map +1 -1
  151. package/lib/esm/hooks/useSidebarGroupCollapse.js.map +1 -1
  152. package/lib/esm/i18n/createI18nInstance.js.map +1 -1
  153. package/lib/esm/i18n/mergeResourceLanguages.js.map +1 -1
  154. package/lib/esm/i18n/resources.js.map +1 -1
  155. package/lib/esm/i18n/useBackofficeFormats.js.map +1 -1
  156. package/lib/esm/i18n/useBackofficeReactTranslation.js.map +1 -1
  157. package/lib/esm/i18n/useReviewStatusLabel.js.map +1 -1
  158. package/lib/esm/modules/base64.js.map +1 -1
  159. package/lib/esm/modules/formatFileSize.js.map +1 -1
  160. package/lib/esm/modules/webauthn.js.map +1 -1
  161. package/lib/esm/node_modules/@babel/runtime/helpers/arrayLikeToArray.js.map +1 -1
  162. package/lib/esm/node_modules/@babel/runtime/helpers/arrayWithoutHoles.js.map +1 -1
  163. package/lib/esm/node_modules/@babel/runtime/helpers/defineProperty.js.map +1 -1
  164. package/lib/esm/node_modules/@babel/runtime/helpers/interopRequireDefault.js.map +1 -1
  165. package/lib/esm/node_modules/@babel/runtime/helpers/iterableToArray.js.map +1 -1
  166. package/lib/esm/node_modules/@babel/runtime/helpers/nonIterableSpread.js.map +1 -1
  167. package/lib/esm/node_modules/@babel/runtime/helpers/objectSpread2.js.map +1 -1
  168. package/lib/esm/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js.map +1 -1
  169. package/lib/esm/node_modules/@babel/runtime/helpers/toConsumableArray.js.map +1 -1
  170. package/lib/esm/node_modules/@babel/runtime/helpers/toPrimitive.js.map +1 -1
  171. package/lib/esm/node_modules/@babel/runtime/helpers/toPropertyKey.js.map +1 -1
  172. package/lib/esm/node_modules/@babel/runtime/helpers/typeof.js.map +1 -1
  173. package/lib/esm/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js.map +1 -1
  174. package/lib/esm/node_modules/@vanilla-extract/recipes/dist/createRuntimeFn-62c9670f.esm.js.map +1 -1
  175. package/lib/esm/node_modules/fbjs/lib/areEqual.js.map +1 -1
  176. package/lib/esm/node_modules/invariant/browser.js.map +1 -1
  177. package/lib/esm/node_modules/relay-test-utils/index.js.map +1 -1
  178. package/lib/esm/node_modules/relay-test-utils/lib/RelayMockPayloadGenerator.js.map +1 -1
  179. package/lib/esm/node_modules/relay-test-utils/lib/RelayModernMockEnvironment.js.map +1 -1
  180. package/lib/esm/node_modules/relay-test-utils/lib/RelayResolverTestUtils.js.map +1 -1
  181. package/lib/esm/node_modules/relay-test-utils/lib/index.js.map +1 -1
  182. package/lib/esm/node_modules/relay-test-utils/lib/unwrapContainer.js.map +1 -1
  183. package/lib/esm/pages/BackofficeAcceptInvitationPage.js.map +1 -1
  184. package/lib/esm/pages/BackofficeDashboardPage.helpers.js.map +1 -1
  185. package/lib/esm/pages/BackofficeDashboardPage.js.map +1 -1
  186. package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js.map +1 -1
  187. package/lib/esm/pages/BackofficeEntityDetailPage.helpers.js.map +1 -1
  188. package/lib/esm/pages/BackofficeEntityDetailPage.js +2 -2
  189. package/lib/esm/pages/BackofficeEntityDetailPage.js.map +1 -1
  190. package/lib/esm/pages/BackofficeEntityDetailPage.view-helpers.js.map +1 -1
  191. package/lib/esm/pages/BackofficeEntityDetailUnknownPageRedirect.js.map +1 -1
  192. package/lib/esm/pages/BackofficeEntityListPage.helpers.js.map +1 -1
  193. package/lib/esm/pages/BackofficeEntityListPage.js.map +1 -1
  194. package/lib/esm/pages/BackofficeHubPage.js.map +1 -1
  195. package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
  196. package/lib/esm/pages/BackofficeLoginPage.js.map +1 -1
  197. package/lib/esm/pages/BackofficePasswordResetCompletePage.js.map +1 -1
  198. package/lib/esm/pages/BackofficePasswordResetRequestPage.js.map +1 -1
  199. package/lib/esm/pages/BackofficeVerifyEmailPage.js.map +1 -1
  200. package/lib/esm/pages/backofficeDashboardPage.css.js +1 -1
  201. package/lib/esm/pages/backofficeEntityDetailPage.css.js +1 -1
  202. package/lib/esm/pages/backofficeEntityListPage.css.js +1 -1
  203. package/lib/esm/pages/detail/BackofficeEntityDetailLayoutContext.js.map +1 -1
  204. package/lib/esm/pages/detail/buildTabsItems.js.map +1 -1
  205. package/lib/esm/pages/detail/pageResolution.js.map +1 -1
  206. package/lib/esm/provider/BackofficeConfigContext.js.map +1 -1
  207. package/lib/esm/provider/BackofficeProvider.js.map +1 -1
  208. package/lib/esm/provider/dashboardRegistrations.js.map +1 -1
  209. package/lib/esm/provider/entityRegistry.js.map +1 -1
  210. package/lib/esm/provider/lazyValue.js.map +1 -1
  211. package/lib/esm/provider/useBackofficeEntityLoader.js.map +1 -1
  212. package/lib/esm/provider/useBackofficeLazyValue.js.map +1 -1
  213. package/lib/esm/relay/RelayProvider.js.map +1 -1
  214. package/lib/esm/relay/connectionUtils.js.map +1 -1
  215. package/lib/esm/relay/createInlineReader.js.map +1 -1
  216. package/lib/esm/relay/envHelpers.js.map +1 -1
  217. package/lib/esm/relay/environment.js.map +1 -1
  218. package/lib/esm/relay/mutationResult.js.map +1 -1
  219. package/lib/esm/router/backofficeAuthPaths.js.map +1 -1
  220. package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
  221. package/lib/esm/storybook/relay/RelayStory.css.js +1 -1
  222. package/lib/esm/storybook/relay/RelayStory.js.map +1 -1
  223. package/lib/esm/storybook/relay/mockResolvers.js.map +1 -1
  224. package/lib/esm/style.css +1 -1
  225. package/lib/esm/subscriptions/useCursorResumableSubscription.js.map +1 -1
  226. package/lib/types/components/backoffice/errors/BackofficeErrorBoundary.stories.d.ts +1 -1
  227. package/lib/types/components/backoffice/errors/BackofficeErrorBoundary.stories.d.ts.map +1 -1
  228. package/lib/types/components/backoffice/overview/backofficeOverviewLayout.css.d.ts.map +1 -1
  229. package/lib/types/components/backoffice/tools/backofficeToolsDocPanel.css.d.ts.map +1 -1
  230. package/package.json +16 -16
@@ -1 +1 @@
1
- {"version":3,"file":"AuthRefreshNotice.js","names":[],"sources":["../../../src/auth/AuthRefreshNotice.tsx"],"sourcesContent":["import { useSyncExternalStore, type JSX } from 'react';\n\nimport { type AuthRefreshState } from '@plumile/auth/authRefreshState.js';\nimport {\n addAuthRefreshStateListener,\n getAuthRefreshState,\n} from '@plumile/auth/shortAccessToken.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\nimport { cx } from '@plumile/ui/theme/tools.js';\n\nimport * as styles from './authRefreshNotice.css.js';\n\nexport type AuthRefreshNoticeMessages = {\n temporarilyUnavailable: string;\n sessionExpired: string;\n};\n\nexport type AuthRefreshNoticeProps = {\n messages: AuthRefreshNoticeMessages;\n className?: string;\n};\n\nconst subscribe = (onStoreChange: () => void): (() => void) => {\n return addAuthRefreshStateListener(() => {\n onStoreChange();\n });\n};\n\nconst getSnapshot = (): AuthRefreshState => {\n return getAuthRefreshState();\n};\n\nexport const useAuthRefreshStateSnapshot = (): AuthRefreshState => {\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n};\n\nexport const AuthRefreshNotice = ({\n messages,\n className,\n}: AuthRefreshNoticeProps): JSX.Element | null => {\n const state = useAuthRefreshStateSnapshot();\n\n if (state.status === 'temporarily_unavailable') {\n return (\n <InlineBanner\n tone=\"warning\"\n className={cx(styles.root, className)}\n role=\"status\"\n ariaLive=\"polite\"\n >\n {messages.temporarilyUnavailable}\n </InlineBanner>\n );\n }\n\n if (state.status === 'session_expired') {\n return (\n <InlineBanner\n tone=\"danger\"\n className={cx(styles.root, className)}\n role=\"status\"\n ariaLive=\"polite\"\n >\n {messages.sessionExpired}\n </InlineBanner>\n );\n }\n\n return null;\n};\n\nexport default AuthRefreshNotice;\n"],"mappings":";;;;;;;AAsBA,IAAM,KAAa,MACV,QAAkC;CACvC,GAAe;EACf,EAGE,UACG,GAAqB,EAGjB,UACJ,EAAqB,GAAW,GAAa,EAAY,EAGrD,KAAqB,EAChC,aACA,mBACgD;CAChD,IAAM,IAAQ,GAA6B;CA4B3C,OA1BI,EAAM,WAAW,4BAEjB,kBAAC,GAAD;EACE,MAAK;EACL,WAAW,EAAG,GAAa,EAAU;EACrC,MAAK;EACL,UAAS;YAER,EAAS;EACG,CAAA,GAIf,EAAM,WAAW,oBAEjB,kBAAC,GAAD;EACE,MAAK;EACL,WAAW,EAAG,GAAa,EAAU;EACrC,MAAK;EACL,UAAS;YAER,EAAS;EACG,CAAA,GAIZ"}
1
+ {"version":3,"file":"AuthRefreshNotice.js","names":[],"sources":["../../../src/auth/AuthRefreshNotice.tsx"],"sourcesContent":["import { useSyncExternalStore, type JSX } from 'react';\n\nimport { type AuthRefreshState } from '@plumile/auth/authRefreshState.js';\nimport {\n addAuthRefreshStateListener,\n getAuthRefreshState,\n} from '@plumile/auth/shortAccessToken.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\nimport { cx } from '@plumile/ui/theme/tools.js';\n\nimport * as styles from './authRefreshNotice.css.js';\n\nexport type AuthRefreshNoticeMessages = {\n temporarilyUnavailable: string;\n sessionExpired: string;\n};\n\nexport type AuthRefreshNoticeProps = {\n messages: AuthRefreshNoticeMessages;\n className?: string;\n};\n\nconst subscribe = (onStoreChange: () => void): (() => void) => {\n return addAuthRefreshStateListener(() => {\n onStoreChange();\n });\n};\n\nconst getSnapshot = (): AuthRefreshState => {\n return getAuthRefreshState();\n};\n\nexport const useAuthRefreshStateSnapshot = (): AuthRefreshState => {\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n};\n\nexport const AuthRefreshNotice = ({\n messages,\n className,\n}: AuthRefreshNoticeProps): JSX.Element | null => {\n const state = useAuthRefreshStateSnapshot();\n\n if (state.status === 'temporarily_unavailable') {\n return (\n <InlineBanner\n tone=\"warning\"\n className={cx(styles.root, className)}\n role=\"status\"\n ariaLive=\"polite\"\n >\n {messages.temporarilyUnavailable}\n </InlineBanner>\n );\n }\n\n if (state.status === 'session_expired') {\n return (\n <InlineBanner\n tone=\"danger\"\n className={cx(styles.root, className)}\n role=\"status\"\n ariaLive=\"polite\"\n >\n {messages.sessionExpired}\n </InlineBanner>\n );\n }\n\n return null;\n};\n\nexport default AuthRefreshNotice;\n"],"mappings":";;;;;;;AAsBA,IAAM,KAAa,MACV,QAAkC;CACvC,EAAc;AAChB,CAAC,GAGG,UACG,EAAoB,GAGhB,UACJ,EAAqB,GAAW,GAAa,CAAW,GAGpD,KAAqB,EAChC,aACA,mBACgD;CAChD,IAAM,IAAQ,EAA4B;CA4B1C,OA1BI,EAAM,WAAW,4BAEjB,kBAAC,GAAD;EACE,MAAK;EACL,WAAW,EAAG,GAAa,CAAS;EACpC,MAAK;EACL,UAAS;YAER,EAAS;CACE,CAAA,IAId,EAAM,WAAW,oBAEjB,kBAAC,GAAD;EACE,MAAK;EACL,WAAW,EAAG,GAAa,CAAS;EACpC,MAAK;EACL,UAAS;YAER,EAAS;CACE,CAAA,IAIX;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"TotpQrCode.js","names":[],"sources":["../../../src/auth/TotpQrCode.tsx"],"sourcesContent":["import type { JSX } from 'react';\nimport { QRCode } from 'react-qr-code';\n\nexport type BuildTotpOtpAuthUriOptions = {\n secret: string;\n issuer: string;\n accountName?: string;\n algorithm?: string;\n digits?: number;\n period?: number;\n};\n\nexport type TotpQrCodeProps = BuildTotpOtpAuthUriOptions & {\n otpauthUrl?: string;\n size?: number;\n};\n\n/**\n *\n */\nexport function buildTotpOtpAuthUri({\n secret,\n issuer,\n accountName,\n algorithm = 'SHA1',\n digits = 6,\n period = 30,\n}: BuildTotpOtpAuthUriOptions): string {\n const label = accountName ?? issuer;\n const params = new URLSearchParams({\n secret,\n issuer,\n algorithm,\n digits: String(digits),\n period: String(period),\n });\n\n return `otpauth://totp/${encodeURIComponent(label)}?${params.toString()}`;\n}\n\nexport const TotpQrCode = ({\n secret,\n issuer,\n accountName,\n otpauthUrl,\n size = 220,\n algorithm,\n digits,\n period,\n}: TotpQrCodeProps): JSX.Element => {\n const otpAuthUri =\n otpauthUrl ??\n buildTotpOtpAuthUri({\n secret,\n issuer,\n accountName,\n algorithm,\n digits,\n period,\n });\n\n return <QRCode value={otpAuthUri} size={size} />;\n};\n\nexport default TotpQrCode;\n"],"mappings":";;;AAoBA,SAAgB,EAAoB,EAClC,WACA,WACA,gBACA,eAAY,QACZ,YAAS,GACT,YAAS,MAC4B;CACrC,IAAM,IAAQ,KAAe,GACvB,IAAS,IAAI,gBAAgB;EACjC;EACA;EACA;EACA,QAAQ,OAAO,EAAO;EACtB,QAAQ,OAAO,EAAO;EACvB,CAAC;CAEF,OAAO,kBAAkB,mBAAmB,EAAM,CAAC,GAAG,EAAO,UAAU;;AAGzE,IAAa,KAAc,EACzB,WACA,WACA,gBACA,eACA,UAAO,KACP,cACA,WACA,gBAaO,kBAAC,GAAD;CAAQ,OAVb,KACA,EAAoB;EAClB;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CAEoC;CAAQ,CAAA"}
1
+ {"version":3,"file":"TotpQrCode.js","names":[],"sources":["../../../src/auth/TotpQrCode.tsx"],"sourcesContent":["import type { JSX } from 'react';\nimport { QRCode } from 'react-qr-code';\n\nexport type BuildTotpOtpAuthUriOptions = {\n secret: string;\n issuer: string;\n accountName?: string;\n algorithm?: string;\n digits?: number;\n period?: number;\n};\n\nexport type TotpQrCodeProps = BuildTotpOtpAuthUriOptions & {\n otpauthUrl?: string;\n size?: number;\n};\n\n/**\n *\n */\nexport function buildTotpOtpAuthUri({\n secret,\n issuer,\n accountName,\n algorithm = 'SHA1',\n digits = 6,\n period = 30,\n}: BuildTotpOtpAuthUriOptions): string {\n const label = accountName ?? issuer;\n const params = new URLSearchParams({\n secret,\n issuer,\n algorithm,\n digits: String(digits),\n period: String(period),\n });\n\n return `otpauth://totp/${encodeURIComponent(label)}?${params.toString()}`;\n}\n\nexport const TotpQrCode = ({\n secret,\n issuer,\n accountName,\n otpauthUrl,\n size = 220,\n algorithm,\n digits,\n period,\n}: TotpQrCodeProps): JSX.Element => {\n const otpAuthUri =\n otpauthUrl ??\n buildTotpOtpAuthUri({\n secret,\n issuer,\n accountName,\n algorithm,\n digits,\n period,\n });\n\n return <QRCode value={otpAuthUri} size={size} />;\n};\n\nexport default TotpQrCode;\n"],"mappings":";;;AAoBA,SAAgB,EAAoB,EAClC,WACA,WACA,gBACA,eAAY,QACZ,YAAS,GACT,YAAS,MAC4B;CACrC,IAAM,IAAQ,KAAe,GACvB,IAAS,IAAI,gBAAgB;EACjC;EACA;EACA;EACA,QAAQ,OAAO,CAAM;EACrB,QAAQ,OAAO,CAAM;CACvB,CAAC;CAED,OAAO,kBAAkB,mBAAmB,CAAK,EAAE,GAAG,EAAO,SAAS;AACxE;AAEA,IAAa,KAAc,EACzB,WACA,WACA,gBACA,eACA,UAAO,KACP,cACA,WACA,gBAaO,kBAAC,GAAD;CAAQ,OAVb,KACA,EAAoB;EAClB;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAEqC;AAAO,CAAA"}
@@ -1,6 +1,6 @@
1
1
  /* empty css */
2
2
  //#region src/auth/authRefreshNotice.css.ts
3
- var e = "txvbqbojf txvbqbph0 txvbqbpzs txvbqbn71 txvbqb11k5 txvbqb18wh txvbqbjyr txvbqb11mo txvbqbbn1 txvbqbryx txvbqbck9";
3
+ var e = "txvbqbqhu txvbqbrff txvbqbry7 txvbqbp5g txvbqb13ik txvbqb1auw txvbqblx6 txvbqb13l3 txvbqbdjn txvbqbtxc txvbqbegv";
4
4
  //#endregion
5
5
  export { e as root };
6
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"AuthPanel.js","names":[],"sources":["../../../../src/auth/login/AuthPanel.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { type JSX, type ReactNode } from 'react';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n title?: string;\n description?: string;\n children: ReactNode;\n footer?: ReactNode;\n};\n\nexport const AuthPanel = ({\n title,\n description,\n children,\n footer,\n}: Props): JSX.Element => {\n return (\n <div className={styles.panel}>\n <div className={styles.block}>\n {title != null ? <h2 className={styles.panelTitle}>{title}</h2> : null}\n {description != null ? (\n <p className={styles.helper}>{description}</p>\n ) : null}\n {children}\n {footer != null ? <div className={styles.footer}>{footer}</div> : null}\n </div>\n </div>\n );\n};\n\nexport default AuthPanel;\n"],"mappings":";;;AAYA,IAAa,KAAa,EACxB,UACA,gBACA,aACA,QAAA,QAGE,kBAAC,OAAD;CAAK,WAAW;WACd,kBAAC,OAAD;EAAK,WAAW;YAAhB;GACG,KAAS,OAAwD,OAAjD,kBAAC,MAAD;IAAI,WAAW;cAAoB;IAAW,CAAA;GAC9D,KAAe,OAEZ,OADF,kBAAC,KAAD;IAAG,WAAW;cAAgB;IAAgB,CAAA;GAE/C;GACA,KAAU,OAAuD,OAAhD,kBAAC,OAAD;IAAK,WAAW;cAAgB;IAAa,CAAA;GAC3D;;CACF,CAAA"}
1
+ {"version":3,"file":"AuthPanel.js","names":[],"sources":["../../../../src/auth/login/AuthPanel.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { type JSX, type ReactNode } from 'react';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n title?: string;\n description?: string;\n children: ReactNode;\n footer?: ReactNode;\n};\n\nexport const AuthPanel = ({\n title,\n description,\n children,\n footer,\n}: Props): JSX.Element => {\n return (\n <div className={styles.panel}>\n <div className={styles.block}>\n {title != null ? <h2 className={styles.panelTitle}>{title}</h2> : null}\n {description != null ? (\n <p className={styles.helper}>{description}</p>\n ) : null}\n {children}\n {footer != null ? <div className={styles.footer}>{footer}</div> : null}\n </div>\n </div>\n );\n};\n\nexport default AuthPanel;\n"],"mappings":";;;AAYA,IAAa,KAAa,EACxB,UACA,gBACA,aACA,QAAA,QAGE,kBAAC,OAAD;CAAK,WAAW;WACd,kBAAC,OAAD;EAAK,WAAW;YAAhB;GACG,KAAS,OAAwD,OAAjD,kBAAC,MAAD;IAAI,WAAW;cAAoB;GAAU,CAAA;GAC7D,KAAe,OAEZ,OADF,kBAAC,KAAD;IAAG,WAAW;cAAgB;GAAe,CAAA;GAE9C;GACA,KAAU,OAAuD,OAAhD,kBAAC,OAAD;IAAK,WAAW;cAAgB;GAAY,CAAA;EAC3D;;AACF,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"EmailCapturePanel.js","names":[],"sources":["../../../../src/auth/login/EmailCapturePanel.tsx"],"sourcesContent":["import { useCallback, type FormEvent, type JSX } from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\n\nimport { AuthPanel } from './AuthPanel.js';\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n email: string;\n errorMessage: string | null;\n isLoading: boolean;\n onEmailChange: (value: string) => void;\n onContinue: () => void;\n onForgotPassword: () => void;\n};\n\nexport const EmailCapturePanel = ({\n email,\n errorMessage,\n isLoading,\n onEmailChange,\n onContinue,\n onForgotPassword,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n onContinue();\n },\n [onContinue],\n );\n\n return (\n <AuthPanel>\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n initialFocus=\"first-form-control\"\n >\n <p className={styles.helper}>{t('auth.emailCapture.description')}</p>\n {errorMessage != null && <FormError>{errorMessage}</FormError>}\n <FormField\n label={t('auth.emailCapture.emailLabel')}\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n onEmailChange(event.target.value);\n }}\n placeholder={t('auth.emailCapture.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n <div className={styles.actionsRow}>\n <Button type=\"submit\" variant=\"primary\" isLoading={isLoading}>\n {t('auth.emailCapture.continue')}\n </Button>\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onForgotPassword}\n >\n {t('auth.emailCapture.forgotPassword')}\n </button>\n </div>\n </Form>\n </AuthPanel>\n );\n};\n"],"mappings":";;;;;;;;;;AAoBA,IAAa,KAAqB,EAChC,UACA,iBACA,cACA,kBACA,eACA,0BACwB;CACxB,IAAM,EAAE,SAAM,GAA+B;CAS7C,OACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,WAAW;EACX,UAZe,GAClB,MAAsC;GAErC,AADA,EAAM,gBAAgB,EACtB,GAAY;KAEd,CAAC,EAAW,CAOE;EACV,cAAa;YAHf;GAKE,kBAAC,KAAD;IAAG,WAAW;cAAgB,EAAE,gCAAgC;IAAK,CAAA;GACpE,KAAgB,QAAQ,kBAAC,GAAD,EAAA,UAAY,GAAyB,CAAA;GAC9D,kBAAC,GAAD;IACE,OAAO,EAAE,+BAA+B;IACxC,MAAK;IACL,MAAK;IACL,OAAO;IACP,WAAW,MAAU;KACnB,EAAc,EAAM,OAAO,MAAM;;IAEnC,aAAa,EAAE,qCAAqC;IACpD,cAAa;IACb,UAAA;IACA,CAAA;GACF,kBAAC,OAAD;IAAK,WAAW;cAAhB,CACE,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAqB;eAChD,EAAE,6BAA6B;KACzB,CAAA,EACT,kBAAC,UAAD;KACE,MAAK;KACL,WAAW;KACX,SAAS;eAER,EAAE,mCAAmC;KAC/B,CAAA,CACL;;GACD;KACG,CAAA"}
1
+ {"version":3,"file":"EmailCapturePanel.js","names":[],"sources":["../../../../src/auth/login/EmailCapturePanel.tsx"],"sourcesContent":["import { useCallback, type FormEvent, type JSX } from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\n\nimport { AuthPanel } from './AuthPanel.js';\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n email: string;\n errorMessage: string | null;\n isLoading: boolean;\n onEmailChange: (value: string) => void;\n onContinue: () => void;\n onForgotPassword: () => void;\n};\n\nexport const EmailCapturePanel = ({\n email,\n errorMessage,\n isLoading,\n onEmailChange,\n onContinue,\n onForgotPassword,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n onContinue();\n },\n [onContinue],\n );\n\n return (\n <AuthPanel>\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n initialFocus=\"first-form-control\"\n >\n <p className={styles.helper}>{t('auth.emailCapture.description')}</p>\n {errorMessage != null && <FormError>{errorMessage}</FormError>}\n <FormField\n label={t('auth.emailCapture.emailLabel')}\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n onEmailChange(event.target.value);\n }}\n placeholder={t('auth.emailCapture.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n <div className={styles.actionsRow}>\n <Button type=\"submit\" variant=\"primary\" isLoading={isLoading}>\n {t('auth.emailCapture.continue')}\n </Button>\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onForgotPassword}\n >\n {t('auth.emailCapture.forgotPassword')}\n </button>\n </div>\n </Form>\n </AuthPanel>\n );\n};\n"],"mappings":";;;;;;;;;;AAoBA,IAAa,KAAqB,EAChC,UACA,iBACA,cACA,kBACA,eACA,0BACwB;CACxB,IAAM,EAAE,SAAM,EAA8B;CAS5C,OACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,WAAW;EACX,UAZe,GAClB,MAAsC;GAErC,AADA,EAAM,eAAe,GACrB,EAAW;EACb,GACA,CAAC,CAAU,CAOG;EACV,cAAa;YAHf;GAKE,kBAAC,KAAD;IAAG,WAAW;cAAgB,EAAE,+BAA+B;GAAK,CAAA;GACnE,KAAgB,QAAQ,kBAAC,GAAD,EAAA,UAAY,EAAwB,CAAA;GAC7D,kBAAC,GAAD;IACE,OAAO,EAAE,8BAA8B;IACvC,MAAK;IACL,MAAK;IACL,OAAO;IACP,WAAW,MAAU;KACnB,EAAc,EAAM,OAAO,KAAK;IAClC;IACA,aAAa,EAAE,oCAAoC;IACnD,cAAa;IACb,UAAA;GACD,CAAA;GACD,kBAAC,OAAD;IAAK,WAAW;cAAhB,CACE,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAqB;eAChD,EAAE,4BAA4B;IACzB,CAAA,GACR,kBAAC,UAAD;KACE,MAAK;KACL,WAAW;KACX,SAAS;eAER,EAAE,kCAAkC;IAC/B,CAAA,CACL;;EACD;IACG,CAAA;AAEf"}
@@ -1 +1 @@
1
- {"version":3,"file":"LoginFlow.js","names":[],"sources":["../../../../src/auth/login/LoginFlow.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n type JSX,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport type {\n AuthMethod,\n OidcProviderKind,\n} from '../../modules/sharedSchemaTypes.js';\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport { MfaChallengeForm } from './MfaChallengeForm.js';\nimport { PasskeyLoginForm } from './PasskeyLoginForm.js';\nimport { MethodChooser } from './MethodChooser.js';\nimport AuthPanel from './AuthPanel.js';\nimport { EmailCapturePanel } from './EmailCapturePanel.js';\nimport { PasswordLoginPanel } from './PasswordLoginPanel.js';\n\nexport type LoginFlowProps = {\n auth: UseAuthReturn;\n oidcProviders: readonly OidcProviderKind[];\n onLoginSuccess: () => void;\n onForgotPassword: () => void;\n};\n\ntype View = 'email' | 'passkey' | 'methods' | 'password' | 'mfa';\n\nexport const LoginFlow = ({\n auth,\n oidcProviders,\n onLoginSuccess,\n onForgotPassword,\n}: LoginFlowProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [email, setEmail] = useState('');\n const [methods, setMethods] = useState<readonly AuthMethod[]>([]);\n const [lockedUntil, setLockedUntil] = useState<string | null>(null);\n const [view, setView] = useState<View>('email');\n const [hasTriedPasskey, setHasTriedPasskey] = useState(false);\n const [localError, setLocalError] = useState<string | null>(null);\n const passkeyAttemptActive = useRef(true);\n\n const loginAdapter = useMemo(() => {\n return {\n ...auth,\n beginAuthentication: async (inputEmail: string) => {\n const result = await auth.beginAuthentication(inputEmail);\n setEmail(inputEmail);\n setMethods(result.methods);\n setLockedUntil(result.lockedUntil);\n return result;\n },\n };\n }, [auth]);\n\n const handleLoginSuccess = useCallback(\n ({ force } = { force: false }) => {\n if (!force && auth.nextStep === 'TOTP') {\n return;\n }\n onLoginSuccess();\n },\n [auth.nextStep, onLoginSuccess],\n );\n\n const isMfaStep = auth.nextStep === 'TOTP' || view === 'mfa';\n const title = isMfaStep\n ? t('auth.loginFlow.title.mfa')\n : t('auth.loginFlow.title.default');\n const subtitle = isMfaStep\n ? t('auth.loginFlow.subtitle.mfa')\n : t('auth.loginFlow.subtitle.default');\n\n const startFlowForEmail = useCallback(\n async (inputEmail: string) => {\n setLocalError(null);\n try {\n const trimmed = inputEmail.trim();\n const result = await auth.beginAuthentication(trimmed);\n setEmail(trimmed);\n setMethods(result.methods);\n setLockedUntil(result.lockedUntil);\n const hasPasskey = result.methods.some((method) => {\n return method === 'PASSKEY';\n });\n\n if (hasPasskey) {\n setView('passkey');\n } else if (result.methods.includes('PASSWORD')) {\n setView('password');\n } else {\n setView('methods');\n }\n } catch {\n setLocalError(t('auth.loginFlow.errors.tryAgain'));\n }\n },\n [auth, t],\n );\n\n useEffect(() => {\n passkeyAttemptActive.current = true;\n const trimmedEmail = email.trim();\n const shouldAttempt =\n view === 'passkey' && !hasTriedPasskey && trimmedEmail !== '';\n\n if (shouldAttempt) {\n setHasTriedPasskey(true);\n const runPasskeyLogin = async () => {\n try {\n const status = await loginAdapter.loginWithPasskey({\n email: trimmedEmail,\n });\n\n if (!passkeyAttemptActive.current) {\n return;\n }\n\n if (status === 'success') {\n handleLoginSuccess();\n return;\n }\n\n if (status === 'mfa-required') {\n setView('mfa');\n return;\n }\n\n setView('methods');\n setLocalError(t('auth.loginFlow.errors.passkeyUnavailable'));\n } catch {\n if (!passkeyAttemptActive.current) {\n return;\n }\n\n setLocalError(t('auth.loginFlow.errors.passkeyUnavailable'));\n setView('methods');\n }\n };\n runPasskeyLogin().catch(() => {\n // Errors are handled inside runPasskeyLogin; ignore any unexpected rethrow.\n });\n }\n\n return () => {\n passkeyAttemptActive.current = false;\n };\n }, [email, handleLoginSuccess, hasTriedPasskey, loginAdapter, t, view]);\n\n let content: JSX.Element;\n\n if (isMfaStep) {\n content = (\n <AuthPanel>\n <MfaChallengeForm\n auth={auth}\n onSuccess={() => {\n handleLoginSuccess({ force: true });\n }}\n onBack={() => {\n auth.reset();\n setView('email');\n }}\n />\n </AuthPanel>\n );\n } else if (view === 'passkey') {\n content = (\n <AuthPanel\n title={t('auth.loginFlow.passkey.title')}\n description={t('auth.loginFlow.passkey.description', { email })}\n >\n <PasskeyLoginForm\n auth={loginAdapter}\n onSuccess={handleLoginSuccess}\n onShowMethods={() => {\n setView('methods');\n }}\n defaultEmail={email}\n isAttemptingPasskey={auth.isLoading}\n />\n </AuthPanel>\n );\n } else if (view === 'methods') {\n content = (\n <AuthPanel title={t('auth.loginFlow.methods.title')}>\n <MethodChooser\n email={email}\n methods={methods}\n lockedUntil={lockedUntil}\n onSelect={(method) => {\n if (method === 'PASSKEY') {\n setView('passkey');\n return;\n }\n if (method === 'PASSWORD') {\n setView('password');\n }\n }}\n onBack={() => {\n setView('email');\n }}\n />\n </AuthPanel>\n );\n } else if (view === 'password') {\n content = (\n <PasswordLoginPanel\n auth={loginAdapter}\n defaultEmail={email}\n onForgotPassword={onForgotPassword}\n onSuccess={handleLoginSuccess}\n providers={oidcProviders}\n />\n );\n } else {\n // email capture only\n content = (\n <EmailCapturePanel\n email={email}\n errorMessage={localError}\n isLoading={auth.isLoading}\n onEmailChange={(value) => {\n setEmail(value);\n setLocalError(null);\n }}\n onContinue={() => {\n const trimmed = email.trim();\n if (trimmed === '') {\n setLocalError(t('auth.loginFlow.errors.emailRequired'));\n return;\n }\n startFlowForEmail(trimmed).catch(() => {\n // startFlowForEmail handles its own errors.\n });\n }}\n onForgotPassword={onForgotPassword}\n />\n );\n }\n\n return (\n <AuthLayout title={title} subtitle={subtitle}>\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"LoginFlow.js","names":[],"sources":["../../../../src/auth/login/LoginFlow.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n type JSX,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport type {\n AuthMethod,\n OidcProviderKind,\n} from '../../modules/sharedSchemaTypes.js';\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport { MfaChallengeForm } from './MfaChallengeForm.js';\nimport { PasskeyLoginForm } from './PasskeyLoginForm.js';\nimport { MethodChooser } from './MethodChooser.js';\nimport AuthPanel from './AuthPanel.js';\nimport { EmailCapturePanel } from './EmailCapturePanel.js';\nimport { PasswordLoginPanel } from './PasswordLoginPanel.js';\n\nexport type LoginFlowProps = {\n auth: UseAuthReturn;\n oidcProviders: readonly OidcProviderKind[];\n onLoginSuccess: () => void;\n onForgotPassword: () => void;\n};\n\ntype View = 'email' | 'passkey' | 'methods' | 'password' | 'mfa';\n\nexport const LoginFlow = ({\n auth,\n oidcProviders,\n onLoginSuccess,\n onForgotPassword,\n}: LoginFlowProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [email, setEmail] = useState('');\n const [methods, setMethods] = useState<readonly AuthMethod[]>([]);\n const [lockedUntil, setLockedUntil] = useState<string | null>(null);\n const [view, setView] = useState<View>('email');\n const [hasTriedPasskey, setHasTriedPasskey] = useState(false);\n const [localError, setLocalError] = useState<string | null>(null);\n const passkeyAttemptActive = useRef(true);\n\n const loginAdapter = useMemo(() => {\n return {\n ...auth,\n beginAuthentication: async (inputEmail: string) => {\n const result = await auth.beginAuthentication(inputEmail);\n setEmail(inputEmail);\n setMethods(result.methods);\n setLockedUntil(result.lockedUntil);\n return result;\n },\n };\n }, [auth]);\n\n const handleLoginSuccess = useCallback(\n ({ force } = { force: false }) => {\n if (!force && auth.nextStep === 'TOTP') {\n return;\n }\n onLoginSuccess();\n },\n [auth.nextStep, onLoginSuccess],\n );\n\n const isMfaStep = auth.nextStep === 'TOTP' || view === 'mfa';\n const title = isMfaStep\n ? t('auth.loginFlow.title.mfa')\n : t('auth.loginFlow.title.default');\n const subtitle = isMfaStep\n ? t('auth.loginFlow.subtitle.mfa')\n : t('auth.loginFlow.subtitle.default');\n\n const startFlowForEmail = useCallback(\n async (inputEmail: string) => {\n setLocalError(null);\n try {\n const trimmed = inputEmail.trim();\n const result = await auth.beginAuthentication(trimmed);\n setEmail(trimmed);\n setMethods(result.methods);\n setLockedUntil(result.lockedUntil);\n const hasPasskey = result.methods.some((method) => {\n return method === 'PASSKEY';\n });\n\n if (hasPasskey) {\n setView('passkey');\n } else if (result.methods.includes('PASSWORD')) {\n setView('password');\n } else {\n setView('methods');\n }\n } catch {\n setLocalError(t('auth.loginFlow.errors.tryAgain'));\n }\n },\n [auth, t],\n );\n\n useEffect(() => {\n passkeyAttemptActive.current = true;\n const trimmedEmail = email.trim();\n const shouldAttempt =\n view === 'passkey' && !hasTriedPasskey && trimmedEmail !== '';\n\n if (shouldAttempt) {\n setHasTriedPasskey(true);\n const runPasskeyLogin = async () => {\n try {\n const status = await loginAdapter.loginWithPasskey({\n email: trimmedEmail,\n });\n\n if (!passkeyAttemptActive.current) {\n return;\n }\n\n if (status === 'success') {\n handleLoginSuccess();\n return;\n }\n\n if (status === 'mfa-required') {\n setView('mfa');\n return;\n }\n\n setView('methods');\n setLocalError(t('auth.loginFlow.errors.passkeyUnavailable'));\n } catch {\n if (!passkeyAttemptActive.current) {\n return;\n }\n\n setLocalError(t('auth.loginFlow.errors.passkeyUnavailable'));\n setView('methods');\n }\n };\n runPasskeyLogin().catch(() => {\n // Errors are handled inside runPasskeyLogin; ignore any unexpected rethrow.\n });\n }\n\n return () => {\n passkeyAttemptActive.current = false;\n };\n }, [email, handleLoginSuccess, hasTriedPasskey, loginAdapter, t, view]);\n\n let content: JSX.Element;\n\n if (isMfaStep) {\n content = (\n <AuthPanel>\n <MfaChallengeForm\n auth={auth}\n onSuccess={() => {\n handleLoginSuccess({ force: true });\n }}\n onBack={() => {\n auth.reset();\n setView('email');\n }}\n />\n </AuthPanel>\n );\n } else if (view === 'passkey') {\n content = (\n <AuthPanel\n title={t('auth.loginFlow.passkey.title')}\n description={t('auth.loginFlow.passkey.description', { email })}\n >\n <PasskeyLoginForm\n auth={loginAdapter}\n onSuccess={handleLoginSuccess}\n onShowMethods={() => {\n setView('methods');\n }}\n defaultEmail={email}\n isAttemptingPasskey={auth.isLoading}\n />\n </AuthPanel>\n );\n } else if (view === 'methods') {\n content = (\n <AuthPanel title={t('auth.loginFlow.methods.title')}>\n <MethodChooser\n email={email}\n methods={methods}\n lockedUntil={lockedUntil}\n onSelect={(method) => {\n if (method === 'PASSKEY') {\n setView('passkey');\n return;\n }\n if (method === 'PASSWORD') {\n setView('password');\n }\n }}\n onBack={() => {\n setView('email');\n }}\n />\n </AuthPanel>\n );\n } else if (view === 'password') {\n content = (\n <PasswordLoginPanel\n auth={loginAdapter}\n defaultEmail={email}\n onForgotPassword={onForgotPassword}\n onSuccess={handleLoginSuccess}\n providers={oidcProviders}\n />\n );\n } else {\n // email capture only\n content = (\n <EmailCapturePanel\n email={email}\n errorMessage={localError}\n isLoading={auth.isLoading}\n onEmailChange={(value) => {\n setEmail(value);\n setLocalError(null);\n }}\n onContinue={() => {\n const trimmed = email.trim();\n if (trimmed === '') {\n setLocalError(t('auth.loginFlow.errors.emailRequired'));\n return;\n }\n startFlowForEmail(trimmed).catch(() => {\n // startFlowForEmail handles its own errors.\n });\n }}\n onForgotPassword={onForgotPassword}\n />\n );\n }\n\n return (\n <AuthLayout title={title} subtitle={subtitle}>\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MethodChooser.js","names":[],"sources":["../../../../src/auth/login/MethodChooser.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { type JSX } from 'react';\nimport { Trans } from 'react-i18next';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { cx } from '@plumile/ui/theme/tools.js';\n\nimport type { AuthMethod } from '../../modules/sharedSchemaTypes.js';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n email: string;\n methods: readonly AuthMethod[];\n lockedUntil: string | null;\n onSelect: (method: AuthMethod) => void;\n onBack: () => void;\n};\n\nexport const MethodChooser = ({\n email,\n methods,\n lockedUntil,\n onSelect,\n onBack,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const isLocked = methods.length === 0;\n const lockedMessage =\n lockedUntil != null\n ? t('auth.methodChooser.lockedWithTime', {\n time: new Date(lockedUntil).toLocaleString(),\n })\n : t('auth.methodChooser.locked');\n\n const methodButtons = methods.map((method) => {\n const label =\n method === 'PASSKEY'\n ? t('auth.methodChooser.methods.passkey')\n : method === 'PASSWORD'\n ? t('auth.methodChooser.methods.password')\n : t('auth.methodChooser.methods.other', {\n method: method.toLowerCase(),\n });\n return (\n <Button\n key={method}\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n onSelect(method);\n }}\n className={cx(styles.fullWidth, styles.brandGhostButton)}\n >\n {label}\n </Button>\n );\n });\n\n return (\n <div className={styles.formSurface}>\n <div className={styles.stack}>\n <p className={styles.helper}>\n <Trans\n i18nKey=\"auth.methodChooser.prompt\"\n values={{ email }}\n components={{ strong: <strong /> }}\n />\n </p>\n {isLocked ? <FormError>{lockedMessage}</FormError> : null}\n {!isLocked ? methodButtons : null}\n <Button\n type=\"button\"\n variant=\"text\"\n onClick={onBack}\n className={styles.inlineLink}\n >\n {t('auth.methodChooser.actions.back')}\n </Button>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;AAoBA,IAAa,KAAiB,EAC5B,UACA,YACA,gBACA,aACA,gBACwB;CACxB,IAAM,EAAE,SAAM,GAA+B,EACvC,IAAW,EAAQ,WAAW,GAC9B,IACJ,KAAe,OAIX,EAAE,4BAA4B,GAH9B,EAAE,qCAAqC,EACrC,MAAM,IAAI,KAAK,EAAY,CAAC,gBAAgB,EAC7C,CAAC,EAGF,IAAgB,EAAQ,KAAK,MAAW;EAC5C,IAAM,IACJ,MAAW,YACP,EAAE,qCAAqC,GACvC,MAAW,aACT,EAAE,sCAAsC,GACxC,EAAE,oCAAoC,EACpC,QAAQ,EAAO,aAAa,EAC7B,CAAC;EACV,OACE,kBAAC,GAAD;GAEE,MAAK;GACL,SAAQ;GACR,eAAe;IACb,EAAS,EAAO;;GAElB,WAAW,EAAG,GAAkB,EAAwB;aAEvD;GACM,EATF,EASE;GAEX;CAEF,OACE,kBAAC,OAAD;EAAK,WAAW;YACd,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,KAAD;KAAG,WAAW;eACZ,kBAAC,GAAD;MACE,SAAQ;MACR,QAAQ,EAAE,UAAO;MACjB,YAAY,EAAE,QAAQ,kBAAC,UAAD,EAAU,CAAA,EAAE;MAClC,CAAA;KACA,CAAA;IACH,IAAW,kBAAC,GAAD,EAAA,UAAY,GAA0B,CAAA,GAAG;IACnD,IAA2B,OAAhB;IACb,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,SAAS;KACT,WAAW;eAEV,EAAE,kCAAkC;KAC9B,CAAA;IACL;;EACF,CAAA"}
1
+ {"version":3,"file":"MethodChooser.js","names":[],"sources":["../../../../src/auth/login/MethodChooser.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { type JSX } from 'react';\nimport { Trans } from 'react-i18next';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { cx } from '@plumile/ui/theme/tools.js';\n\nimport type { AuthMethod } from '../../modules/sharedSchemaTypes.js';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n email: string;\n methods: readonly AuthMethod[];\n lockedUntil: string | null;\n onSelect: (method: AuthMethod) => void;\n onBack: () => void;\n};\n\nexport const MethodChooser = ({\n email,\n methods,\n lockedUntil,\n onSelect,\n onBack,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const isLocked = methods.length === 0;\n const lockedMessage =\n lockedUntil != null\n ? t('auth.methodChooser.lockedWithTime', {\n time: new Date(lockedUntil).toLocaleString(),\n })\n : t('auth.methodChooser.locked');\n\n const methodButtons = methods.map((method) => {\n const label =\n method === 'PASSKEY'\n ? t('auth.methodChooser.methods.passkey')\n : method === 'PASSWORD'\n ? t('auth.methodChooser.methods.password')\n : t('auth.methodChooser.methods.other', {\n method: method.toLowerCase(),\n });\n return (\n <Button\n key={method}\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n onSelect(method);\n }}\n className={cx(styles.fullWidth, styles.brandGhostButton)}\n >\n {label}\n </Button>\n );\n });\n\n return (\n <div className={styles.formSurface}>\n <div className={styles.stack}>\n <p className={styles.helper}>\n <Trans\n i18nKey=\"auth.methodChooser.prompt\"\n values={{ email }}\n components={{ strong: <strong /> }}\n />\n </p>\n {isLocked ? <FormError>{lockedMessage}</FormError> : null}\n {!isLocked ? methodButtons : null}\n <Button\n type=\"button\"\n variant=\"text\"\n onClick={onBack}\n className={styles.inlineLink}\n >\n {t('auth.methodChooser.actions.back')}\n </Button>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;AAoBA,IAAa,KAAiB,EAC5B,UACA,YACA,gBACA,aACA,gBACwB;CACxB,IAAM,EAAE,SAAM,EAA8B,GACtC,IAAW,EAAQ,WAAW,GAC9B,IACJ,KAAe,OAIX,EAAE,2BAA2B,IAH7B,EAAE,qCAAqC,EACrC,MAAM,IAAI,KAAK,CAAW,EAAE,eAAe,EAC7C,CAAC,GAGD,IAAgB,EAAQ,KAAK,MAAW;EAC5C,IAAM,IACJ,MAAW,YACP,EAAE,oCAAoC,IACtC,MAAW,aACT,EAAE,qCAAqC,IACvC,EAAE,oCAAoC,EACpC,QAAQ,EAAO,YAAY,EAC7B,CAAC;EACT,OACE,kBAAC,GAAD;GAEE,MAAK;GACL,SAAQ;GACR,eAAe;IACb,EAAS,CAAM;GACjB;GACA,WAAW,EAAG,GAAkB,CAAuB;aAEtD;EACK,GATD,CASC;CAEZ,CAAC;CAED,OACE,kBAAC,OAAD;EAAK,WAAW;YACd,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,KAAD;KAAG,WAAW;eACZ,kBAAC,GAAD;MACE,SAAQ;MACR,QAAQ,EAAE,SAAM;MAChB,YAAY,EAAE,QAAQ,kBAAC,UAAD,CAAS,CAAA,EAAE;KAClC,CAAA;IACA,CAAA;IACF,IAAW,kBAAC,GAAD,EAAA,UAAY,EAAyB,CAAA,IAAI;IACnD,IAA2B,OAAhB;IACb,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,SAAS;KACT,WAAW;eAEV,EAAE,iCAAiC;IAC9B,CAAA;GACL;;CACF,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"MfaChallengeForm.js","names":[],"sources":["../../../../src/auth/login/MfaChallengeForm.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\n\nimport type { TotpCredentials, UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: Pick<\n UseAuthReturn,\n 'completeMfa' | 'isLoading' | 'error' | 'emailHint' | 'reset' | 'clearError'\n >;\n onSuccess: () => void;\n onBack: () => void;\n};\n\nexport const MfaChallengeForm = ({\n auth,\n onSuccess,\n onBack,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [code, setCode] = useState('');\n const [localError, setLocalError] = useState<string | null>(null);\n\n // Clear any stale errors when the MFA form is shown\n useEffect(() => {\n auth.clearError();\n setLocalError(null);\n }, [auth]);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setLocalError(null);\n\n const trimmed = code.trim();\n if (trimmed.length < 4) {\n setLocalError(t('auth.mfa.errors.shortCode'));\n return;\n }\n\n try {\n const credentials: TotpCredentials = {\n code: trimmed,\n };\n await auth.completeMfa(credentials);\n onSuccess();\n } catch {\n setLocalError(t('auth.mfa.errors.verificationFailed'));\n }\n },\n [auth, code, onSuccess, t],\n );\n\n const helper =\n auth.emailHint != null\n ? t('auth.mfa.helper.withEmail', { email: auth.emailHint })\n : t('auth.mfa.helper.default');\n\n const formError = localError;\n\n const handleSubmitEvent = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n handleSubmit(event).catch(() => {\n return undefined;\n });\n },\n [handleSubmit],\n );\n\n return (\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmitEvent}\n noValidate\n initialFocus=\"first-form-control\"\n >\n <div className={styles.stack}>\n <p className={styles.helper}>{helper}</p>\n {formError != null ? <FormError>{formError}</FormError> : null}\n <FormField\n label={t('auth.mfa.form.label')}\n name=\"code\"\n type=\"text\"\n value={code}\n onChange={(event) => {\n setCode(event.target.value);\n setLocalError(null);\n }}\n placeholder={t('auth.mfa.form.placeholder')}\n autoComplete=\"one-time-code\"\n required\n />\n </div>\n <div className={styles.actionsRow}>\n <Button\n type=\"button\"\n variant=\"text\"\n size=\"small\"\n className={styles.inlineLink}\n onClick={() => {\n auth.reset();\n onBack();\n }}\n >\n {t('auth.mfa.actions.back')}\n </Button>\n <Button type=\"submit\" size=\"large\" isLoading={auth.isLoading}>\n {t('auth.mfa.actions.submit')}\n </Button>\n </div>\n </Form>\n );\n};\n"],"mappings":";;;;;;;;;AA4BA,IAAa,KAAoB,EAC/B,SACA,cACA,gBACwB;CACxB,IAAM,EAAE,SAAM,GAA+B,EACvC,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,CAAC,GAAY,KAAiB,EAAwB,KAAK;CAGjE,QAAgB;EAEd,AADA,EAAK,YAAY,EACjB,EAAc,KAAK;IAClB,CAAC,EAAK,CAAC;CAEV,IAAM,IAAe,EACnB,OAAO,MAAsC;EAE3C,AADA,EAAM,gBAAgB,EACtB,EAAc,KAAK;EAEnB,IAAM,IAAU,EAAK,MAAM;EAC3B,IAAI,EAAQ,SAAS,GAAG;GACtB,EAAc,EAAE,4BAA4B,CAAC;GAC7C;;EAGF,IAAI;GACF,IAAM,IAA+B,EACnC,MAAM,GACP;GAED,AADA,MAAM,EAAK,YAAY,EAAY,EACnC,GAAW;UACL;GACN,EAAc,EAAE,qCAAqC,CAAC;;IAG1D;EAAC;EAAM;EAAM;EAAW;EAAE,CAC3B,EAEK,IACJ,EAAK,aAAa,OAEd,EAAE,0BAA0B,GAD5B,EAAE,6BAA6B,EAAE,OAAO,EAAK,WAAW,CAAC,EAGzD,IAAY;CAWlB,OACE,kBAAC,GAAD;EACE,WAAW;EACX,UAZsB,GACvB,MAAsC;GACrC,EAAa,EAAM,CAAC,YAAY,GAE9B;KAEJ,CAAC,EAAa,CAMF;EACV,YAAA;EACA,cAAa;YAJf,CAME,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,KAAD;KAAG,WAAW;eAAgB;KAAW,CAAA;IACxC,KAAa,OAA4C,OAArC,kBAAC,GAAD,EAAA,UAAY,GAAsB,CAAA;IACvD,kBAAC,GAAD;KACE,OAAO,EAAE,sBAAsB;KAC/B,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAQ,EAAM,OAAO,MAAM,EAC3B,EAAc,KAAK;;KAErB,aAAa,EAAE,4BAA4B;KAC3C,cAAa;KACb,UAAA;KACA,CAAA;IACE;MACN,kBAAC,OAAD;GAAK,WAAW;aAAhB,CACE,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACR,MAAK;IACL,WAAW;IACX,eAAe;KAEb,AADA,EAAK,OAAO,EACZ,GAAQ;;cAGT,EAAE,wBAAwB;IACpB,CAAA,EACT,kBAAC,GAAD;IAAQ,MAAK;IAAS,MAAK;IAAQ,WAAW,EAAK;cAChD,EAAE,0BAA0B;IACtB,CAAA,CACL;KACD"}
1
+ {"version":3,"file":"MfaChallengeForm.js","names":[],"sources":["../../../../src/auth/login/MfaChallengeForm.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\n\nimport type { TotpCredentials, UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: Pick<\n UseAuthReturn,\n 'completeMfa' | 'isLoading' | 'error' | 'emailHint' | 'reset' | 'clearError'\n >;\n onSuccess: () => void;\n onBack: () => void;\n};\n\nexport const MfaChallengeForm = ({\n auth,\n onSuccess,\n onBack,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [code, setCode] = useState('');\n const [localError, setLocalError] = useState<string | null>(null);\n\n // Clear any stale errors when the MFA form is shown\n useEffect(() => {\n auth.clearError();\n setLocalError(null);\n }, [auth]);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setLocalError(null);\n\n const trimmed = code.trim();\n if (trimmed.length < 4) {\n setLocalError(t('auth.mfa.errors.shortCode'));\n return;\n }\n\n try {\n const credentials: TotpCredentials = {\n code: trimmed,\n };\n await auth.completeMfa(credentials);\n onSuccess();\n } catch {\n setLocalError(t('auth.mfa.errors.verificationFailed'));\n }\n },\n [auth, code, onSuccess, t],\n );\n\n const helper =\n auth.emailHint != null\n ? t('auth.mfa.helper.withEmail', { email: auth.emailHint })\n : t('auth.mfa.helper.default');\n\n const formError = localError;\n\n const handleSubmitEvent = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n handleSubmit(event).catch(() => {\n return undefined;\n });\n },\n [handleSubmit],\n );\n\n return (\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmitEvent}\n noValidate\n initialFocus=\"first-form-control\"\n >\n <div className={styles.stack}>\n <p className={styles.helper}>{helper}</p>\n {formError != null ? <FormError>{formError}</FormError> : null}\n <FormField\n label={t('auth.mfa.form.label')}\n name=\"code\"\n type=\"text\"\n value={code}\n onChange={(event) => {\n setCode(event.target.value);\n setLocalError(null);\n }}\n placeholder={t('auth.mfa.form.placeholder')}\n autoComplete=\"one-time-code\"\n required\n />\n </div>\n <div className={styles.actionsRow}>\n <Button\n type=\"button\"\n variant=\"text\"\n size=\"small\"\n className={styles.inlineLink}\n onClick={() => {\n auth.reset();\n onBack();\n }}\n >\n {t('auth.mfa.actions.back')}\n </Button>\n <Button type=\"submit\" size=\"large\" isLoading={auth.isLoading}>\n {t('auth.mfa.actions.submit')}\n </Button>\n </div>\n </Form>\n );\n};\n"],"mappings":";;;;;;;;;AA4BA,IAAa,KAAoB,EAC/B,SACA,cACA,gBACwB;CACxB,IAAM,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAM,KAAW,EAAS,EAAE,GAC7B,CAAC,GAAY,KAAiB,EAAwB,IAAI;CAGhE,QAAgB;EAEd,AADA,EAAK,WAAW,GAChB,EAAc,IAAI;CACpB,GAAG,CAAC,CAAI,CAAC;CAET,IAAM,IAAe,EACnB,OAAO,MAAsC;EAE3C,AADA,EAAM,eAAe,GACrB,EAAc,IAAI;EAElB,IAAM,IAAU,EAAK,KAAK;EAC1B,IAAI,EAAQ,SAAS,GAAG;GACtB,EAAc,EAAE,2BAA2B,CAAC;GAC5C;EACF;EAEA,IAAI;GACF,IAAM,IAA+B,EACnC,MAAM,EACR;GAEA,AADA,MAAM,EAAK,YAAY,CAAW,GAClC,EAAU;EACZ,QAAQ;GACN,EAAc,EAAE,oCAAoC,CAAC;EACvD;CACF,GACA;EAAC;EAAM;EAAM;EAAW;CAAC,CAC3B,GAEM,IACJ,EAAK,aAAa,OAEd,EAAE,yBAAyB,IAD3B,EAAE,6BAA6B,EAAE,OAAO,EAAK,UAAU,CAAC,GAGxD,IAAY;CAWlB,OACE,kBAAC,GAAD;EACE,WAAW;EACX,UAZsB,GACvB,MAAsC;GACrC,EAAa,CAAK,EAAE,YAAY,CAEhC,CAAC;EACH,GACA,CAAC,CAAY,CAMD;EACV,YAAA;EACA,cAAa;YAJf,CAME,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,KAAD;KAAG,WAAW;eAAgB;IAAU,CAAA;IACvC,KAAa,OAA4C,OAArC,kBAAC,GAAD,EAAA,UAAY,EAAqB,CAAA;IACtD,kBAAC,GAAD;KACE,OAAO,EAAE,qBAAqB;KAC9B,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAQ,EAAM,OAAO,KAAK,GAC1B,EAAc,IAAI;KACpB;KACA,aAAa,EAAE,2BAA2B;KAC1C,cAAa;KACb,UAAA;IACD,CAAA;GACE;MACL,kBAAC,OAAD;GAAK,WAAW;aAAhB,CACE,kBAAC,GAAD;IACE,MAAK;IACL,SAAQ;IACR,MAAK;IACL,WAAW;IACX,eAAe;KAEb,AADA,EAAK,MAAM,GACX,EAAO;IACT;cAEC,EAAE,uBAAuB;GACpB,CAAA,GACR,kBAAC,GAAD;IAAQ,MAAK;IAAS,MAAK;IAAQ,WAAW,EAAK;cAChD,EAAE,yBAAyB;GACtB,CAAA,CACL;IACD;;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"OidcButtons.js","names":[],"sources":["../../../../src/auth/login/OidcButtons.tsx"],"sourcesContent":["import { type JSX } from 'react';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\n\nimport type { OidcProviderKind } from '../../modules/sharedSchemaTypes.js';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './loginPage.css.js';\n\nconst OIDC_START_PATH = '/auth/oidc/start';\n\ntype Props = {\n providers: readonly OidcProviderKind[];\n};\n\nexport const OidcButtons = ({ providers }: Props): JSX.Element | null => {\n const { t } = useBackofficeReactTranslation();\n\n if (providers.length === 0) {\n return null;\n }\n\n return (\n <div className={styles.stack}>\n {providers.map((provider) => {\n let label = t('auth.oidc.buttons.generic');\n if (provider === 'GOOGLE') {\n label = t('auth.oidc.buttons.google');\n } else if (provider === 'APPLE') {\n label = t('auth.oidc.buttons.apple');\n }\n const providerName = provider.toLowerCase();\n return (\n <Button\n key={provider}\n type=\"button\"\n variant=\"secondary\"\n className={styles.brandGhostButton}\n onClick={() => {\n window.location.assign(\n `${OIDC_START_PATH}?provider=${providerName}`,\n );\n }}\n >\n {label}\n </Button>\n );\n })}\n </div>\n );\n};\n"],"mappings":";;;;;AASA,IAAM,IAAkB,oBAMX,KAAe,EAAE,mBAA2C;CACvE,IAAM,EAAE,SAAM,GAA+B;CAM7C,OAJI,EAAU,WAAW,IAChB,OAIP,kBAAC,OAAD;EAAK,WAAW;YACb,EAAU,KAAK,MAAa;GAC3B,IAAI,IAAQ,EAAE,4BAA4B;GAC1C,AAAI,MAAa,WACf,IAAQ,EAAE,2BAA2B,GAC5B,MAAa,YACtB,IAAQ,EAAE,0BAA0B;GAEtC,IAAM,IAAe,EAAS,aAAa;GAC3C,OACE,kBAAC,GAAD;IAEE,MAAK;IACL,SAAQ;IACR,WAAW;IACX,eAAe;KACb,OAAO,SAAS,OACd,GAAG,EAAgB,YAAY,IAChC;;cAGF;IACM,EAXF,EAWE;IAEX;EACE,CAAA"}
1
+ {"version":3,"file":"OidcButtons.js","names":[],"sources":["../../../../src/auth/login/OidcButtons.tsx"],"sourcesContent":["import { type JSX } from 'react';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\n\nimport type { OidcProviderKind } from '../../modules/sharedSchemaTypes.js';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './loginPage.css.js';\n\nconst OIDC_START_PATH = '/auth/oidc/start';\n\ntype Props = {\n providers: readonly OidcProviderKind[];\n};\n\nexport const OidcButtons = ({ providers }: Props): JSX.Element | null => {\n const { t } = useBackofficeReactTranslation();\n\n if (providers.length === 0) {\n return null;\n }\n\n return (\n <div className={styles.stack}>\n {providers.map((provider) => {\n let label = t('auth.oidc.buttons.generic');\n if (provider === 'GOOGLE') {\n label = t('auth.oidc.buttons.google');\n } else if (provider === 'APPLE') {\n label = t('auth.oidc.buttons.apple');\n }\n const providerName = provider.toLowerCase();\n return (\n <Button\n key={provider}\n type=\"button\"\n variant=\"secondary\"\n className={styles.brandGhostButton}\n onClick={() => {\n window.location.assign(\n `${OIDC_START_PATH}?provider=${providerName}`,\n );\n }}\n >\n {label}\n </Button>\n );\n })}\n </div>\n );\n};\n"],"mappings":";;;;;AASA,IAAM,IAAkB,oBAMX,KAAe,EAAE,mBAA2C;CACvE,IAAM,EAAE,SAAM,EAA8B;CAM5C,OAJI,EAAU,WAAW,IAChB,OAIP,kBAAC,OAAD;EAAK,WAAW;YACb,EAAU,KAAK,MAAa;GAC3B,IAAI,IAAQ,EAAE,2BAA2B;GACzC,AAAI,MAAa,WACf,IAAQ,EAAE,0BAA0B,IAC3B,MAAa,YACtB,IAAQ,EAAE,yBAAyB;GAErC,IAAM,IAAe,EAAS,YAAY;GAC1C,OACE,kBAAC,GAAD;IAEE,MAAK;IACL,SAAQ;IACR,WAAW;IACX,eAAe;KACb,OAAO,SAAS,OACd,GAAG,EAAgB,YAAY,GACjC;IACF;cAEC;GACK,GAXD,CAWC;EAEZ,CAAC;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"PasskeyLoginForm.js","names":[],"sources":["../../../../src/auth/login/PasskeyLoginForm.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\n\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: Pick<\n UseAuthReturn,\n | 'loginWithPasskey'\n | 'isLoading'\n | 'error'\n | 'emailHint'\n | 'nextStep'\n | 'beginAuthentication'\n | 'lockedUntil'\n | 'availableMethods'\n >;\n onSuccess: () => void;\n defaultEmail?: string;\n isAttemptingPasskey?: boolean;\n onShowMethods?: () => void;\n};\n\nexport const PasskeyLoginForm = ({\n auth,\n onSuccess,\n defaultEmail,\n isAttemptingPasskey = false,\n onShowMethods,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [email, setEmail] = useState(auth.emailHint ?? '');\n const [localError, setLocalError] = useState<string | null>(null);\n\n useEffect(() => {\n if (auth.emailHint != null && auth.emailHint !== '') {\n setEmail(auth.emailHint);\n } else if (defaultEmail != null && defaultEmail !== '') {\n setEmail(defaultEmail);\n }\n }, [auth.emailHint, defaultEmail]);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setLocalError(null);\n\n if (email.trim() === '') {\n setLocalError(t('auth.passkey.errors.emailRequired'));\n return;\n }\n\n try {\n const result = await auth.beginAuthentication(email.trim());\n if (Array.isArray(result.methods) && result.methods.length === 0) {\n const lockedUntilMessage =\n result.lockedUntil != null\n ? t('auth.passkey.errors.lockedWithTime', {\n time: new Date(result.lockedUntil).toLocaleString(),\n })\n : t('auth.passkey.errors.locked');\n setLocalError(lockedUntilMessage);\n return;\n }\n if (\n Array.isArray(result.methods) &&\n !result.methods.includes('PASSKEY')\n ) {\n setLocalError(t('auth.passkey.errors.notAvailable'));\n return;\n }\n\n const status = await auth.loginWithPasskey({ email: email.trim() });\n if (status === 'success') {\n onSuccess();\n }\n } catch {\n setLocalError(t('auth.passkey.errors.failed'));\n }\n },\n [auth, email, onSuccess, t],\n );\n\n const formError = localError;\n\n const handleSubmitEvent = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n handleSubmit(event).catch(() => {\n return undefined;\n });\n },\n [handleSubmit],\n );\n\n return (\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmitEvent}\n noValidate\n initialFocus=\"first-form-control\"\n >\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.passkey.helper')}</p>\n {formError != null ? <FormError>{formError}</FormError> : null}\n <FormField\n label={t('auth.passkey.form.emailLabel')}\n name=\"passkey-email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n setLocalError(null);\n }}\n placeholder={t('auth.passkey.form.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n </div>\n <div className={styles.actionsRow}>\n <Button type=\"submit\" variant=\"primary\" isLoading={auth.isLoading}>\n {isAttemptingPasskey\n ? t('auth.passkey.actions.submitting')\n : t('auth.passkey.actions.submit')}\n </Button>\n {onShowMethods != null ? (\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onShowMethods}\n >\n {t('auth.passkey.actions.showMethods')}\n </button>\n ) : null}\n </div>\n </Form>\n );\n};\n"],"mappings":";;;;;;;;;AAqCA,IAAa,KAAoB,EAC/B,SACA,cACA,iBACA,yBAAsB,IACtB,uBACwB;CACxB,IAAM,EAAE,SAAM,GAA+B,EACvC,CAAC,GAAO,KAAY,EAAS,EAAK,aAAa,GAAG,EAClD,CAAC,GAAY,KAAiB,EAAwB,KAAK;CAEjE,QAAgB;EACd,AAAI,EAAK,aAAa,QAAQ,EAAK,cAAc,KAC/C,EAAS,EAAK,UAAU,GACf,KAAgB,QAAQ,MAAiB,MAClD,EAAS,EAAa;IAEvB,CAAC,EAAK,WAAW,EAAa,CAAC;CAElC,IAAM,IAAe,EACnB,OAAO,MAAsC;EAI3C,IAHA,EAAM,gBAAgB,EACtB,EAAc,KAAK,EAEf,EAAM,MAAM,KAAK,IAAI;GACvB,EAAc,EAAE,oCAAoC,CAAC;GACrD;;EAGF,IAAI;GACF,IAAM,IAAS,MAAM,EAAK,oBAAoB,EAAM,MAAM,CAAC;GAC3D,IAAI,MAAM,QAAQ,EAAO,QAAQ,IAAI,EAAO,QAAQ,WAAW,GAAG;IAOhE,EALE,EAAO,eAAe,OAIlB,EAAE,6BAA6B,GAH/B,EAAE,sCAAsC,EACtC,MAAM,IAAI,KAAK,EAAO,YAAY,CAAC,gBAAgB,EACpD,CAAC,CAEyB;IACjC;;GAEF,IACE,MAAM,QAAQ,EAAO,QAAQ,IAC7B,CAAC,EAAO,QAAQ,SAAS,UAAU,EACnC;IACA,EAAc,EAAE,mCAAmC,CAAC;IACpD;;GAIF,AAAI,MADiB,EAAK,iBAAiB,EAAE,OAAO,EAAM,MAAM,EAAE,CAAC,KACpD,aACb,GAAW;UAEP;GACN,EAAc,EAAE,6BAA6B,CAAC;;IAGlD;EAAC;EAAM;EAAO;EAAW;EAAE,CAC5B,EAEK,IAAY;CAWlB,OACE,kBAAC,GAAD;EACE,WAAW;EACX,UAZsB,GACvB,MAAsC;GACrC,EAAa,EAAM,CAAC,YAAY,GAE9B;KAEJ,CAAC,EAAa,CAMF;EACV,YAAA;EACA,cAAa;YAJf,CAME,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,KAAD;KAAG,WAAW;eAAgB,EAAE,sBAAsB;KAAK,CAAA;IAC1D,KAAa,OAA4C,OAArC,kBAAC,GAAD,EAAA,UAAY,GAAsB,CAAA;IACvD,kBAAC,GAAD;KACE,OAAO,EAAE,+BAA+B;KACxC,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAS,EAAM,OAAO,MAAM,EAC5B,EAAc,KAAK;;KAErB,aAAa,EAAE,qCAAqC;KACpD,cAAa;KACb,UAAA;KACA,CAAA;IACE;MACN,kBAAC,OAAD;GAAK,WAAW;aAAhB,CACE,kBAAC,GAAD;IAAQ,MAAK;IAAS,SAAQ;IAAU,WAAW,EAAK;cAElD,EADH,IACK,oCACA,8BAA8B;IAC7B,CAAA,EACR,KAAiB,OAQd,OAPF,kBAAC,UAAD;IACE,MAAK;IACL,WAAW;IACX,SAAS;cAER,EAAE,mCAAmC;IAC/B,CAAA,CAEP;KACD"}
1
+ {"version":3,"file":"PasskeyLoginForm.js","names":[],"sources":["../../../../src/auth/login/PasskeyLoginForm.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\n\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: Pick<\n UseAuthReturn,\n | 'loginWithPasskey'\n | 'isLoading'\n | 'error'\n | 'emailHint'\n | 'nextStep'\n | 'beginAuthentication'\n | 'lockedUntil'\n | 'availableMethods'\n >;\n onSuccess: () => void;\n defaultEmail?: string;\n isAttemptingPasskey?: boolean;\n onShowMethods?: () => void;\n};\n\nexport const PasskeyLoginForm = ({\n auth,\n onSuccess,\n defaultEmail,\n isAttemptingPasskey = false,\n onShowMethods,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [email, setEmail] = useState(auth.emailHint ?? '');\n const [localError, setLocalError] = useState<string | null>(null);\n\n useEffect(() => {\n if (auth.emailHint != null && auth.emailHint !== '') {\n setEmail(auth.emailHint);\n } else if (defaultEmail != null && defaultEmail !== '') {\n setEmail(defaultEmail);\n }\n }, [auth.emailHint, defaultEmail]);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setLocalError(null);\n\n if (email.trim() === '') {\n setLocalError(t('auth.passkey.errors.emailRequired'));\n return;\n }\n\n try {\n const result = await auth.beginAuthentication(email.trim());\n if (Array.isArray(result.methods) && result.methods.length === 0) {\n const lockedUntilMessage =\n result.lockedUntil != null\n ? t('auth.passkey.errors.lockedWithTime', {\n time: new Date(result.lockedUntil).toLocaleString(),\n })\n : t('auth.passkey.errors.locked');\n setLocalError(lockedUntilMessage);\n return;\n }\n if (\n Array.isArray(result.methods) &&\n !result.methods.includes('PASSKEY')\n ) {\n setLocalError(t('auth.passkey.errors.notAvailable'));\n return;\n }\n\n const status = await auth.loginWithPasskey({ email: email.trim() });\n if (status === 'success') {\n onSuccess();\n }\n } catch {\n setLocalError(t('auth.passkey.errors.failed'));\n }\n },\n [auth, email, onSuccess, t],\n );\n\n const formError = localError;\n\n const handleSubmitEvent = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n handleSubmit(event).catch(() => {\n return undefined;\n });\n },\n [handleSubmit],\n );\n\n return (\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmitEvent}\n noValidate\n initialFocus=\"first-form-control\"\n >\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.passkey.helper')}</p>\n {formError != null ? <FormError>{formError}</FormError> : null}\n <FormField\n label={t('auth.passkey.form.emailLabel')}\n name=\"passkey-email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n setLocalError(null);\n }}\n placeholder={t('auth.passkey.form.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n </div>\n <div className={styles.actionsRow}>\n <Button type=\"submit\" variant=\"primary\" isLoading={auth.isLoading}>\n {isAttemptingPasskey\n ? t('auth.passkey.actions.submitting')\n : t('auth.passkey.actions.submit')}\n </Button>\n {onShowMethods != null ? (\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onShowMethods}\n >\n {t('auth.passkey.actions.showMethods')}\n </button>\n ) : null}\n </div>\n </Form>\n );\n};\n"],"mappings":";;;;;;;;;AAqCA,IAAa,KAAoB,EAC/B,SACA,cACA,iBACA,yBAAsB,IACtB,uBACwB;CACxB,IAAM,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAO,KAAY,EAAS,EAAK,aAAa,EAAE,GACjD,CAAC,GAAY,KAAiB,EAAwB,IAAI;CAEhE,QAAgB;EACd,AAAI,EAAK,aAAa,QAAQ,EAAK,cAAc,KAC/C,EAAS,EAAK,SAAS,IACd,KAAgB,QAAQ,MAAiB,MAClD,EAAS,CAAY;CAEzB,GAAG,CAAC,EAAK,WAAW,CAAY,CAAC;CAEjC,IAAM,IAAe,EACnB,OAAO,MAAsC;EAI3C,IAHA,EAAM,eAAe,GACrB,EAAc,IAAI,GAEd,EAAM,KAAK,MAAM,IAAI;GACvB,EAAc,EAAE,mCAAmC,CAAC;GACpD;EACF;EAEA,IAAI;GACF,IAAM,IAAS,MAAM,EAAK,oBAAoB,EAAM,KAAK,CAAC;GAC1D,IAAI,MAAM,QAAQ,EAAO,OAAO,KAAK,EAAO,QAAQ,WAAW,GAAG;IAOhE,EALE,EAAO,eAAe,OAIlB,EAAE,4BAA4B,IAH9B,EAAE,sCAAsC,EACtC,MAAM,IAAI,KAAK,EAAO,WAAW,EAAE,eAAe,EACpD,CAAC,CAEyB;IAChC;GACF;GACA,IACE,MAAM,QAAQ,EAAO,OAAO,KAC5B,CAAC,EAAO,QAAQ,SAAS,SAAS,GAClC;IACA,EAAc,EAAE,kCAAkC,CAAC;IACnD;GACF;GAGA,AAAI,MADiB,EAAK,iBAAiB,EAAE,OAAO,EAAM,KAAK,EAAE,CAAC,MACnD,aACb,EAAU;EAEd,QAAQ;GACN,EAAc,EAAE,4BAA4B,CAAC;EAC/C;CACF,GACA;EAAC;EAAM;EAAO;EAAW;CAAC,CAC5B,GAEM,IAAY;CAWlB,OACE,kBAAC,GAAD;EACE,WAAW;EACX,UAZsB,GACvB,MAAsC;GACrC,EAAa,CAAK,EAAE,YAAY,CAEhC,CAAC;EACH,GACA,CAAC,CAAY,CAMD;EACV,YAAA;EACA,cAAa;YAJf,CAME,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,KAAD;KAAG,WAAW;eAAgB,EAAE,qBAAqB;IAAK,CAAA;IACzD,KAAa,OAA4C,OAArC,kBAAC,GAAD,EAAA,UAAY,EAAqB,CAAA;IACtD,kBAAC,GAAD;KACE,OAAO,EAAE,8BAA8B;KACvC,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAS,EAAM,OAAO,KAAK,GAC3B,EAAc,IAAI;KACpB;KACA,aAAa,EAAE,oCAAoC;KACnD,cAAa;KACb,UAAA;IACD,CAAA;GACE;MACL,kBAAC,OAAD;GAAK,WAAW;aAAhB,CACE,kBAAC,GAAD;IAAQ,MAAK;IAAS,SAAQ;IAAU,WAAW,EAAK;cAElD,EADH,IACK,oCACA,6BAA6B;GAC7B,CAAA,GACP,KAAiB,OAQd,OAPF,kBAAC,UAAD;IACE,MAAK;IACL,WAAW;IACX,SAAS;cAER,EAAE,kCAAkC;GAC/B,CAAA,CAEP;IACD;;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordLoginPanel.js","names":[],"sources":["../../../../src/auth/login/PasswordLoginPanel.tsx"],"sourcesContent":["import { type JSX } from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { LoginForm } from '@plumile/ui/atomic/organisms/login_form/LoginForm.js';\nimport { type LoginFormAuthAdapter } from '@plumile/ui/atomic/organisms/login_form/useLoginForm.js';\n\nimport type { OidcProviderKind } from '../../modules/sharedSchemaTypes.js';\n\nimport { AuthPanel } from './AuthPanel.js';\nimport { OidcButtons } from './OidcButtons.js';\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: LoginFormAuthAdapter;\n defaultEmail: string;\n onForgotPassword: () => void;\n onSuccess: () => void;\n providers: readonly OidcProviderKind[];\n};\n\nexport const PasswordLoginPanel = ({\n auth,\n defaultEmail,\n onForgotPassword,\n onSuccess,\n providers,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n return (\n <AuthPanel title={t('auth.passwordLogin.title')}>\n <div className={styles.formSurface}>\n <LoginForm\n auth={auth}\n onSuccess={onSuccess}\n defaultEmail={defaultEmail}\n />\n <div className={styles.actionsRow}>\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onForgotPassword}\n >\n {t('auth.passwordLogin.forgotPassword')}\n </button>\n </div>\n <OidcButtons providers={providers} />\n </div>\n </AuthPanel>\n );\n};\n"],"mappings":";;;;;;;AAoBA,IAAa,KAAsB,EACjC,SACA,iBACA,qBACA,cACA,mBACwB;CACxB,IAAM,EAAE,SAAM,GAA+B;CAC7C,OACE,kBAAC,GAAD;EAAW,OAAO,EAAE,2BAA2B;YAC7C,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,GAAD;KACQ;KACK;KACG;KACd,CAAA;IACF,kBAAC,OAAD;KAAK,WAAW;eACd,kBAAC,UAAD;MACE,MAAK;MACL,WAAW;MACX,SAAS;gBAER,EAAE,oCAAoC;MAChC,CAAA;KACL,CAAA;IACN,kBAAC,GAAD,EAAwB,cAAa,CAAA;IACjC;;EACI,CAAA"}
1
+ {"version":3,"file":"PasswordLoginPanel.js","names":[],"sources":["../../../../src/auth/login/PasswordLoginPanel.tsx"],"sourcesContent":["import { type JSX } from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { LoginForm } from '@plumile/ui/atomic/organisms/login_form/LoginForm.js';\nimport { type LoginFormAuthAdapter } from '@plumile/ui/atomic/organisms/login_form/useLoginForm.js';\n\nimport type { OidcProviderKind } from '../../modules/sharedSchemaTypes.js';\n\nimport { AuthPanel } from './AuthPanel.js';\nimport { OidcButtons } from './OidcButtons.js';\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: LoginFormAuthAdapter;\n defaultEmail: string;\n onForgotPassword: () => void;\n onSuccess: () => void;\n providers: readonly OidcProviderKind[];\n};\n\nexport const PasswordLoginPanel = ({\n auth,\n defaultEmail,\n onForgotPassword,\n onSuccess,\n providers,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n return (\n <AuthPanel title={t('auth.passwordLogin.title')}>\n <div className={styles.formSurface}>\n <LoginForm\n auth={auth}\n onSuccess={onSuccess}\n defaultEmail={defaultEmail}\n />\n <div className={styles.actionsRow}>\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onForgotPassword}\n >\n {t('auth.passwordLogin.forgotPassword')}\n </button>\n </div>\n <OidcButtons providers={providers} />\n </div>\n </AuthPanel>\n );\n};\n"],"mappings":";;;;;;;AAoBA,IAAa,KAAsB,EACjC,SACA,iBACA,qBACA,cACA,mBACwB;CACxB,IAAM,EAAE,SAAM,EAA8B;CAC5C,OACE,kBAAC,GAAD;EAAW,OAAO,EAAE,0BAA0B;YAC5C,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,GAAD;KACQ;KACK;KACG;IACf,CAAA;IACD,kBAAC,OAAD;KAAK,WAAW;eACd,kBAAC,UAAD;MACE,MAAK;MACL,WAAW;MACX,SAAS;gBAER,EAAE,mCAAmC;KAChC,CAAA;IACL,CAAA;IACL,kBAAC,GAAD,EAAwB,aAAY,CAAA;GACjC;;CACI,CAAA;AAEf"}
@@ -2,7 +2,7 @@
2
2
  /* empty css */
3
3
  /* empty css */
4
4
  //#region src/auth/login/loginPage.css.ts
5
- var e = "txvbqbdr8 txvbqbf6i txvbqbffw", t = "txvbqbdr8 txvbqbf6i txvbqb17w0", n = "txvbqb19dn txvbqb9j txvbqbm9g txvbqblzp", r = "txvbqbey txvbqb19dn txvbqbdr8 txvbqbff6 txvbqbq1l txvbqbn84", i = "txvbqb197r txvbqbi1s txvbqbdxd txvbqb2is txvbqb19e7", a = "txvbqbey txvbqbdr8 txvbqbf91 txvbqbffj txvbqbjus txvbqbq0v", o = "w8yhmy0 txvbqb1933 txvbqb1g5 txvbqb2e3 txvbqb19d9 txvbqbv txvbqbfd0 txvbqbux3 txvbqb3f txvbqb7h txvbqb76 txvbqb7t txvbqb1bwh txvbqb1czl", s = "txvbqbypl txvbqbzn6 txvbqb10kr txvbqbvwu txvbqbabd txvbqba5l txvbqbalh txvbqbahi", c = "txvbqbdr8 txvbqbf6i txvbqbffw", l = "txvbqb17w0", u = "txvbqbm9g txvbqbam txvbqbfdd txvbqb19d9 txvbqbkvm", d = "txvbqbq18", f = "w8yhmy1 txvbqb1cw txvbqb1w1 txvbqb2et txvbqb19d9 txvbqb1983 txvbqb7h txvbqb75 txvbqb7t";
5
+ var e = "txvbqbfpn txvbqbh4x txvbqbheb", t = "txvbqbfpn txvbqbh4x txvbqb19uf", n = "txvbqb1bg3 txvbqb9j txvbqbo7v txvbqbny4", r = "txvbqbey txvbqb1bg3 txvbqbfpn txvbqbhdl txvbqbs00 txvbqbp6j", i = "txvbqb1b9r txvbqbk07 txvbqbfvs txvbqb2wi txvbqb1bk3", a = "txvbqbey txvbqbfpn txvbqbh7g txvbqbhdy txvbqblt7 txvbqbrza", o = "w8yhmy0 txvbqb1b4r txvbqb1tv txvbqb2rt txvbqb1bhb txvbqbv txvbqbhbf txvbqbwvi txvbqb3f txvbqb7h txvbqb76 txvbqb7t txvbqb1etp txvbqb1gct", s = "txvbqb10o0 txvbqb11ll txvbqb12j6 txvbqbxv9 txvbqbc7z txvbqbc27 txvbqbci3 txvbqbce4", c = "txvbqbfpn txvbqbh4x txvbqbheb", l = "txvbqb19uf", u = "txvbqbo7v txvbqbam txvbqbhbs txvbqb1bhb txvbqbmu1", d = "txvbqbrzn", f = "w8yhmy1 txvbqb1f2 txvbqb29r txvbqb2sj txvbqb1bhb txvbqb1b9n txvbqb7h txvbqb75 txvbqb7t";
6
6
  //#endregion
7
7
  export { a as actionsRow, c as block, f as brandGhostButton, r as divider, i as dividerLine, d as footer, t as formSurface, l as fullWidth, n as helper, o as inlineLink, s as panel, u as panelTitle, e as stack };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"loginPage.css.js","names":[],"sources":["../../../../src/auth/login/loginPage.css.ts"],"sourcesContent":["import { style } from '@vanilla-extract/css';\nimport { sprinkles, stateSprinkles } from '@plumile/ui/theme/sprinkles.css.js';\nimport { vars } from '@plumile/ui/theme/themeContract.css.js';\n\nexport const stack = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const formSurface = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n width: 'full',\n});\n\nexport const helper = sprinkles({\n color: 'brandDarkGray',\n fontSize: 'sm',\n margin: 0,\n lineHeight: 1.6,\n});\n\nexport const divider = sprinkles({\n alignItems: 'center',\n color: 'brandDarkGray',\n display: 'flex',\n gap: 2,\n marginTop: 5,\n marginBottom: 3,\n});\n\nexport const dividerLine = sprinkles({\n backgroundColor: 'brandPrimaryRed',\n height: 'px',\n flex: 1,\n borderRadius: 'full',\n opacity: 35,\n});\n\nexport const actionsRow = sprinkles({\n alignItems: 'center',\n display: 'flex',\n flexWrap: 'wrap',\n gap: 3,\n justifyContent: 'space-between',\n marginTop: 3,\n});\n\nexport const inlineLink = style([\n sprinkles({\n backgroundColor: 'transparent',\n borderWidth: 0,\n borderStyle: 'none',\n color: 'brandPrimaryRed',\n cursor: 'pointer',\n fontWeight: 'semibold',\n padding: 0,\n textDecoration: 'none',\n transitionProperty: 'colors',\n transitionDuration: 150,\n transitionTimingFunction: 'ease',\n }),\n stateSprinkles({\n color: { hover: 'brandSecondaryOrange' },\n textDecoration: { hover: 'underline' },\n }),\n]);\n\nexport const panel = sprinkles({\n borderTopLeftRadius: 'none',\n borderTopRightRadius: 'none',\n borderBottomLeftRadius: '2xl',\n borderBottomRightRadius: '2xl',\n paddingX: 6,\n paddingY: 6,\n});\n\nexport const block = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const fullWidth = sprinkles({\n width: 'full',\n});\n\nexport const panelTitle = sprinkles({\n margin: 0,\n fontSize: 'xl',\n fontWeight: 'bold',\n color: 'brandPrimaryRed',\n letterSpacing: 'tight',\n});\n\nexport const footer = sprinkles({\n marginTop: 4,\n});\n\nexport const brandGhostButton = style([\n sprinkles({\n borderColor: 'brandPrimaryRed',\n borderWidth: 'px',\n borderStyle: 'solid',\n color: 'brandPrimaryRed',\n backgroundColor: 'brandLightGray',\n transitionProperty: 'colors',\n transitionDuration: 120,\n transitionTimingFunction: 'ease',\n }),\n {\n selectors: {\n '&:hover:not(:disabled)': {\n backgroundColor: `color-mix(in srgb, ${vars.colors.brandPrimaryRed} 8%, transparent)`,\n color: vars.colors.brandSecondaryOrange,\n borderColor: vars.colors.brandSecondaryOrange,\n },\n },\n },\n]);\n"],"mappings":""}
1
+ {"version":3,"file":"loginPage.css.js","names":[],"sources":["../../../../src/auth/login/loginPage.css.ts"],"sourcesContent":["import { style } from '@vanilla-extract/css';\nimport { sprinkles, stateSprinkles } from '@plumile/ui/theme/sprinkles.css.js';\nimport { vars } from '@plumile/ui/theme/themeContract.css.js';\n\nexport const stack = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const formSurface = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n width: 'full',\n});\n\nexport const helper = sprinkles({\n color: 'textSecondary',\n fontSize: 'sm',\n margin: 0,\n lineHeight: 1.6,\n});\n\nexport const divider = sprinkles({\n alignItems: 'center',\n color: 'textSecondary',\n display: 'flex',\n gap: 2,\n marginTop: 5,\n marginBottom: 3,\n});\n\nexport const dividerLine = sprinkles({\n backgroundColor: 'tonePrimaryBorder',\n height: 'px',\n flex: 1,\n borderRadius: 'full',\n opacity: 35,\n});\n\nexport const actionsRow = sprinkles({\n alignItems: 'center',\n display: 'flex',\n flexWrap: 'wrap',\n gap: 3,\n justifyContent: 'space-between',\n marginTop: 3,\n});\n\nexport const inlineLink = style([\n sprinkles({\n backgroundColor: 'transparent',\n borderWidth: 0,\n borderStyle: 'none',\n color: 'tonePrimaryText',\n cursor: 'pointer',\n fontWeight: 'semibold',\n padding: 0,\n textDecoration: 'none',\n transitionProperty: 'colors',\n transitionDuration: 150,\n transitionTimingFunction: 'ease',\n }),\n stateSprinkles({\n color: { hover: 'tonePrimaryText' },\n textDecoration: { hover: 'underline' },\n }),\n]);\n\nexport const panel = sprinkles({\n borderTopLeftRadius: 'none',\n borderTopRightRadius: 'none',\n borderBottomLeftRadius: '2xl',\n borderBottomRightRadius: '2xl',\n paddingX: 6,\n paddingY: 6,\n});\n\nexport const block = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const fullWidth = sprinkles({\n width: 'full',\n});\n\nexport const panelTitle = sprinkles({\n margin: 0,\n fontSize: 'xl',\n fontWeight: 'bold',\n color: 'tonePrimaryText',\n letterSpacing: 'tight',\n});\n\nexport const footer = sprinkles({\n marginTop: 4,\n});\n\nexport const brandGhostButton = style([\n sprinkles({\n borderColor: 'tonePrimaryBorder',\n borderWidth: 'px',\n borderStyle: 'solid',\n color: 'tonePrimaryText',\n backgroundColor: 'tonePrimarySurface',\n transitionProperty: 'colors',\n transitionDuration: 120,\n transitionTimingFunction: 'ease',\n }),\n {\n selectors: {\n '&:hover:not(:disabled)': {\n backgroundColor: vars.colors.tonePrimarySurface,\n color: vars.colors.tonePrimaryText,\n borderColor: vars.colors.tonePrimaryBorder,\n },\n },\n },\n]);\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"synchronizeAuthStatusQuery.js","names":[],"sources":["../../../../src/auth/login/synchronizeAuthStatusQuery.ts"],"sourcesContent":["import RelayRuntime, {\n type GraphQLTaggedNode,\n type IEnvironment,\n type OperationType,\n} from 'relay-runtime';\n\nconst { fetchQuery } = RelayRuntime;\n\ntype AuthStatusQueryResponse = {\n readonly isLoggedIn?: boolean | null;\n};\n\n/**\n * Forces a fresh auth-status read from network to avoid stale cache guards\n * right after login mutations complete.\n */\nexport async function synchronizeAuthStatusQuery<TQuery extends OperationType>(\n environment: IEnvironment,\n query: GraphQLTaggedNode,\n): Promise<boolean> {\n const response = await fetchQuery<TQuery>(\n environment,\n query,\n {},\n { fetchPolicy: 'network-only' },\n ).toPromise();\n\n const isLoggedIn = (response as AuthStatusQueryResponse | null | undefined)\n ?.isLoggedIn;\n return isLoggedIn === true;\n}\n"],"mappings":";;AAMA,IAAM,EAAE,YAAA,MAAe;AAUvB,eAAsB,EACpB,GACA,GACkB;CAUlB,QAFoB,MAPG,EACrB,GACA,GACA,EAAE,EACF,EAAE,aAAa,gBAAgB,CAChC,CAAC,WAAW,GAGT,eACkB"}
1
+ {"version":3,"file":"synchronizeAuthStatusQuery.js","names":[],"sources":["../../../../src/auth/login/synchronizeAuthStatusQuery.ts"],"sourcesContent":["import RelayRuntime, {\n type GraphQLTaggedNode,\n type IEnvironment,\n type OperationType,\n} from 'relay-runtime';\n\nconst { fetchQuery } = RelayRuntime;\n\ntype AuthStatusQueryResponse = {\n readonly isLoggedIn?: boolean | null;\n};\n\n/**\n * Forces a fresh auth-status read from network to avoid stale cache guards\n * right after login mutations complete.\n */\nexport async function synchronizeAuthStatusQuery<TQuery extends OperationType>(\n environment: IEnvironment,\n query: GraphQLTaggedNode,\n): Promise<boolean> {\n const response = await fetchQuery<TQuery>(\n environment,\n query,\n {},\n { fetchPolicy: 'network-only' },\n ).toPromise();\n\n const isLoggedIn = (response as AuthStatusQueryResponse | null | undefined)\n ?.isLoggedIn;\n return isLoggedIn === true;\n}\n"],"mappings":";;AAMA,IAAM,EAAE,YAAA,MAAe;AAUvB,eAAsB,EACpB,GACA,GACkB;CAUlB,QAFoB,MAPG,EACrB,GACA,GACA,CAAC,GACD,EAAE,aAAa,eAAe,CAChC,EAAE,UAAU,IAGR,eACkB;AACxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"AcceptInvitationScreen.js","names":[],"sources":["../../../../src/auth/pages/AcceptInvitationScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\nimport { MfaChallengeForm } from '../login/MfaChallengeForm.js';\nimport AuthPanel from '../login/AuthPanel.js';\nimport * as styles from '../login/loginPage.css.js';\n\ntype AcceptanceState = 'pending' | 'mfa' | 'completed' | 'error' | 'idle';\n\ntype Props = {\n auth: UseAuthReturn;\n onSuccessRedirect: () => void;\n onBackToLogin: () => void;\n token?: string;\n};\n\nexport const AcceptInvitationScreen = ({\n auth,\n onSuccessRedirect,\n onBackToLogin,\n token,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const { acceptInvitation } = auth;\n const [status, setStatus] = useState<AcceptanceState>('idle');\n const [password, setPassword] = useState('');\n const [passwordConfirmation, setPasswordConfirmation] = useState('');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (resolvedToken === '') {\n setErrorMessage(t('auth.acceptInvitation.errors.missingToken'));\n setStatus('error');\n return;\n }\n\n if (password !== passwordConfirmation) {\n setErrorMessage(t('auth.acceptInvitation.errors.passwordMismatch'));\n setStatus('error');\n return;\n }\n\n setStatus('pending');\n setErrorMessage(null);\n setIsSubmitting(true);\n\n // eslint-disable-next-line no-void\n void acceptInvitation({\n token: resolvedToken,\n password,\n passwordConfirmation,\n })\n .then((result) => {\n if (result === 'mfa-required') {\n setStatus('mfa');\n return;\n }\n setStatus('completed');\n onSuccessRedirect();\n })\n .catch(() => {\n setStatus('error');\n setErrorMessage(t('auth.acceptInvitation.errors.default'));\n })\n .finally(() => {\n setIsSubmitting(false);\n });\n },\n [\n acceptInvitation,\n onSuccessRedirect,\n password,\n passwordConfirmation,\n resolvedToken,\n t,\n ],\n );\n\n const handleMfaSuccess = useCallback(() => {\n setStatus('completed');\n onSuccessRedirect();\n }, [onSuccessRedirect]);\n\n const handleRetry = useCallback(() => {\n setStatus('idle');\n setErrorMessage(null);\n setIsSubmitting(false);\n }, []);\n\n if (status === 'mfa') {\n return (\n <AuthLayout\n title={t('auth.acceptInvitation.mfaTitle')}\n subtitle={t('auth.acceptInvitation.mfaSubtitle')}\n >\n <MfaChallengeForm\n auth={auth}\n onSuccess={handleMfaSuccess}\n onBack={() => {\n auth.reset();\n handleRetry();\n }}\n />\n </AuthLayout>\n );\n }\n\n let content: JSX.Element;\n if (status === 'completed') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.acceptInvitation.status.success')}\n </p>\n </div>\n );\n } else {\n content = (\n <AuthPanel description={t('auth.acceptInvitation.subtitle')}>\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n noValidate\n initialFocus=\"first-form-control\"\n >\n {errorMessage != null ? <FormError>{errorMessage}</FormError> : null}\n <FormField\n label={t('auth.acceptInvitation.form.passwordLabel')}\n name=\"password\"\n type=\"password\"\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.passwordPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <FormField\n label={t('auth.acceptInvitation.form.confirmLabel')}\n name=\"password-confirmation\"\n type=\"password\"\n value={passwordConfirmation}\n onChange={(event) => {\n setPasswordConfirmation(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.confirmPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {status === 'pending'\n ? t('auth.acceptInvitation.status.workingButton')\n : t('auth.acceptInvitation.form.submit')}\n </Button>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.acceptInvitation.actions.backToLogin')}\n </Button>\n </Form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout title={t('auth.acceptInvitation.title')}>{content}</AuthLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AcceptInvitationScreen.js","names":[],"sources":["../../../../src/auth/pages/AcceptInvitationScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\nimport { MfaChallengeForm } from '../login/MfaChallengeForm.js';\nimport AuthPanel from '../login/AuthPanel.js';\nimport * as styles from '../login/loginPage.css.js';\n\ntype AcceptanceState = 'pending' | 'mfa' | 'completed' | 'error' | 'idle';\n\ntype Props = {\n auth: UseAuthReturn;\n onSuccessRedirect: () => void;\n onBackToLogin: () => void;\n token?: string;\n};\n\nexport const AcceptInvitationScreen = ({\n auth,\n onSuccessRedirect,\n onBackToLogin,\n token,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const { acceptInvitation } = auth;\n const [status, setStatus] = useState<AcceptanceState>('idle');\n const [password, setPassword] = useState('');\n const [passwordConfirmation, setPasswordConfirmation] = useState('');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (resolvedToken === '') {\n setErrorMessage(t('auth.acceptInvitation.errors.missingToken'));\n setStatus('error');\n return;\n }\n\n if (password !== passwordConfirmation) {\n setErrorMessage(t('auth.acceptInvitation.errors.passwordMismatch'));\n setStatus('error');\n return;\n }\n\n setStatus('pending');\n setErrorMessage(null);\n setIsSubmitting(true);\n\n // eslint-disable-next-line no-void\n void acceptInvitation({\n token: resolvedToken,\n password,\n passwordConfirmation,\n })\n .then((result) => {\n if (result === 'mfa-required') {\n setStatus('mfa');\n return;\n }\n setStatus('completed');\n onSuccessRedirect();\n })\n .catch(() => {\n setStatus('error');\n setErrorMessage(t('auth.acceptInvitation.errors.default'));\n })\n .finally(() => {\n setIsSubmitting(false);\n });\n },\n [\n acceptInvitation,\n onSuccessRedirect,\n password,\n passwordConfirmation,\n resolvedToken,\n t,\n ],\n );\n\n const handleMfaSuccess = useCallback(() => {\n setStatus('completed');\n onSuccessRedirect();\n }, [onSuccessRedirect]);\n\n const handleRetry = useCallback(() => {\n setStatus('idle');\n setErrorMessage(null);\n setIsSubmitting(false);\n }, []);\n\n if (status === 'mfa') {\n return (\n <AuthLayout\n title={t('auth.acceptInvitation.mfaTitle')}\n subtitle={t('auth.acceptInvitation.mfaSubtitle')}\n >\n <MfaChallengeForm\n auth={auth}\n onSuccess={handleMfaSuccess}\n onBack={() => {\n auth.reset();\n handleRetry();\n }}\n />\n </AuthLayout>\n );\n }\n\n let content: JSX.Element;\n if (status === 'completed') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.acceptInvitation.status.success')}\n </p>\n </div>\n );\n } else {\n content = (\n <AuthPanel description={t('auth.acceptInvitation.subtitle')}>\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n noValidate\n initialFocus=\"first-form-control\"\n >\n {errorMessage != null ? <FormError>{errorMessage}</FormError> : null}\n <FormField\n label={t('auth.acceptInvitation.form.passwordLabel')}\n name=\"password\"\n type=\"password\"\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.passwordPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <FormField\n label={t('auth.acceptInvitation.form.confirmLabel')}\n name=\"password-confirmation\"\n type=\"password\"\n value={passwordConfirmation}\n onChange={(event) => {\n setPasswordConfirmation(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.confirmPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {status === 'pending'\n ? t('auth.acceptInvitation.status.workingButton')\n : t('auth.acceptInvitation.form.submit')}\n </Button>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.acceptInvitation.actions.backToLogin')}\n </Button>\n </Form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout title={t('auth.acceptInvitation.title')}>{content}</AuthLayout>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordResetCompleteScreen.js","names":[],"sources":["../../../../src/auth/pages/PasswordResetCompleteScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport * as styles from '../login/loginPage.css.js';\nimport AuthPanel from '../login/AuthPanel.js';\n\nconst MIN_PASSWORD_LENGTH = 8;\n\ntype Props = {\n onBackToLogin: () => void;\n onCompletePasswordReset: (input: {\n newPassword: string;\n token: string;\n }) => Promise<boolean>;\n token?: string;\n};\n\nexport const PasswordResetCompleteScreen = ({\n onBackToLogin,\n onCompletePasswordReset,\n token,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [password, setPassword] = useState('');\n const [passwordConfirm, setPasswordConfirm] = useState('');\n const [status, setStatus] = useState<'idle' | 'completed'>('idle');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (resolvedToken === '') {\n setError(t('auth.passwordResetComplete.errors.missingToken'));\n return;\n }\n\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(\n t('auth.passwordResetComplete.errors.minLength', {\n minLength: MIN_PASSWORD_LENGTH,\n }),\n );\n return;\n }\n\n if (password !== passwordConfirm) {\n setError(t('auth.passwordResetComplete.errors.mismatch'));\n return;\n }\n\n setIsSubmitting(true);\n\n const completePasswordReset = async (): Promise<void> => {\n try {\n const success = await onCompletePasswordReset({\n newPassword: password,\n token: resolvedToken,\n });\n if (success) {\n setStatus('completed');\n } else {\n setError(t('auth.passwordResetComplete.errors.invalid'));\n }\n } catch (mutationError) {\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.passwordResetComplete.errors.invalid'),\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n completePasswordReset().catch(() => {\n return undefined;\n });\n },\n [onCompletePasswordReset, password, passwordConfirm, resolvedToken, t],\n );\n\n let content: JSX.Element;\n if (status === 'completed') {\n content = (\n <AuthPanel\n title={t('auth.passwordResetComplete.success.title')}\n description={t('auth.passwordResetComplete.success.description')}\n footer={\n <Button\n type=\"button\"\n variant=\"secondary\"\n className={styles.brandGhostButton}\n onClick={onBackToLogin}\n >\n {t('auth.passwordResetComplete.success.action')}\n </Button>\n }\n >\n <p className={styles.helper}>\n {t('auth.passwordResetComplete.success.helper')}\n </p>\n </AuthPanel>\n );\n } else {\n content = (\n <AuthPanel\n title={t('auth.passwordResetComplete.form.title')}\n description={t('auth.passwordResetComplete.form.description')}\n >\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n noValidate\n initialFocus=\"first-form-control\"\n >\n {error != null ? <FormError>{error}</FormError> : null}\n <FormField\n label={t('auth.passwordResetComplete.form.passwordLabel')}\n name=\"new-password\"\n type=\"password\"\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n setError(null);\n }}\n placeholder={t(\n 'auth.passwordResetComplete.form.passwordPlaceholder',\n )}\n autoComplete=\"new-password\"\n required\n />\n <FormField\n label={t('auth.passwordResetComplete.form.confirmLabel')}\n name=\"confirm-password\"\n type=\"password\"\n value={passwordConfirm}\n onChange={(event) => {\n setPasswordConfirm(event.target.value);\n setError(null);\n }}\n placeholder={t(\n 'auth.passwordResetComplete.form.confirmPlaceholder',\n )}\n autoComplete=\"new-password\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {t('auth.passwordResetComplete.form.submit')}\n </Button>\n </Form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.passwordResetComplete.title')}\n subtitle={t('auth.passwordResetComplete.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;AAmBA,IAAM,IAAsB,GAWf,KAA+B,EAC1C,kBACA,4BACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAA+B,EACvC,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAiB,KAAsB,EAAS,GAAG,EACpD,CAAC,GAAQ,KAAa,EAA+B,OAAO,EAC5D,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAGF,IADY,gBAAgB,OAAO,SAAS,OAC5C,CAAO,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC,EAEL,IAAe,GAClB,MAAsC;EAIrC,IAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,MAAkB,IAAI;GACxB,EAAS,EAAE,iDAAiD,CAAC;GAC7D;;EAGF,IAAI,EAAS,SAAS,GAAqB;GACzC,EACE,EAAE,+CAA+C,EAC/C,WAAW,GACZ,CAAC,CACH;GACD;;EAGF,IAAI,MAAa,GAAiB;GAChC,EAAS,EAAE,6CAA6C,CAAC;GACzD;;EA2BF,AAxBA,EAAgB,GAAK,GAwBrB,YAtByD;GACvD,IAAI;IAKF,AAAI,MAJkB,EAAwB;KAC5C,aAAa;KACb,OAAO;KACR,CAAC,GAEA,EAAU,YAAY,GAEtB,EAAS,EAAE,4CAA4C,CAAC;YAEnD,GAAe;IACtB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,4CAA4C,CACnD;aACO;IACR,EAAgB,GAAM;;MAIH,CAAC,YAAY,GAElC;IAEJ;EAAC;EAAyB;EAAU;EAAiB;EAAe;EAAE,CACvE,EAEG;CAyEJ,OAxEA,AAsBE,IAtBE,MAAW,cAEX,kBAAC,GAAD;EACE,OAAO,EAAE,2CAA2C;EACpD,aAAa,EAAE,iDAAiD;EAChE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,WAAW;GACX,SAAS;aAER,EAAE,4CAA4C;GACxC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,4CAA4C;GAC7C,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EACE,OAAO,EAAE,wCAAwC;EACjD,aAAa,EAAE,8CAA8C;YAE7D,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;aAJf;IAMG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,gDAAgD;KACzD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAY,EAAM,OAAO,MAAM,EAC/B,EAAS,KAAK;;KAEhB,aAAa,EACX,sDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KACE,OAAO,EAAE,+CAA+C;KACxD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAmB,EAAM,OAAO,MAAM,EACtC,EAAS,KAAK;;KAEhB,aAAa,EACX,qDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,yCAAyC;KACrC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EACE,OAAO,EAAE,mCAAmC;EAC5C,UAAU,EAAE,sCAAsC;YAEjD;EACU,CAAA"}
1
+ {"version":3,"file":"PasswordResetCompleteScreen.js","names":[],"sources":["../../../../src/auth/pages/PasswordResetCompleteScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport * as styles from '../login/loginPage.css.js';\nimport AuthPanel from '../login/AuthPanel.js';\n\nconst MIN_PASSWORD_LENGTH = 8;\n\ntype Props = {\n onBackToLogin: () => void;\n onCompletePasswordReset: (input: {\n newPassword: string;\n token: string;\n }) => Promise<boolean>;\n token?: string;\n};\n\nexport const PasswordResetCompleteScreen = ({\n onBackToLogin,\n onCompletePasswordReset,\n token,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [password, setPassword] = useState('');\n const [passwordConfirm, setPasswordConfirm] = useState('');\n const [status, setStatus] = useState<'idle' | 'completed'>('idle');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (resolvedToken === '') {\n setError(t('auth.passwordResetComplete.errors.missingToken'));\n return;\n }\n\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(\n t('auth.passwordResetComplete.errors.minLength', {\n minLength: MIN_PASSWORD_LENGTH,\n }),\n );\n return;\n }\n\n if (password !== passwordConfirm) {\n setError(t('auth.passwordResetComplete.errors.mismatch'));\n return;\n }\n\n setIsSubmitting(true);\n\n const completePasswordReset = async (): Promise<void> => {\n try {\n const success = await onCompletePasswordReset({\n newPassword: password,\n token: resolvedToken,\n });\n if (success) {\n setStatus('completed');\n } else {\n setError(t('auth.passwordResetComplete.errors.invalid'));\n }\n } catch (mutationError) {\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.passwordResetComplete.errors.invalid'),\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n completePasswordReset().catch(() => {\n return undefined;\n });\n },\n [onCompletePasswordReset, password, passwordConfirm, resolvedToken, t],\n );\n\n let content: JSX.Element;\n if (status === 'completed') {\n content = (\n <AuthPanel\n title={t('auth.passwordResetComplete.success.title')}\n description={t('auth.passwordResetComplete.success.description')}\n footer={\n <Button\n type=\"button\"\n variant=\"secondary\"\n className={styles.brandGhostButton}\n onClick={onBackToLogin}\n >\n {t('auth.passwordResetComplete.success.action')}\n </Button>\n }\n >\n <p className={styles.helper}>\n {t('auth.passwordResetComplete.success.helper')}\n </p>\n </AuthPanel>\n );\n } else {\n content = (\n <AuthPanel\n title={t('auth.passwordResetComplete.form.title')}\n description={t('auth.passwordResetComplete.form.description')}\n >\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n noValidate\n initialFocus=\"first-form-control\"\n >\n {error != null ? <FormError>{error}</FormError> : null}\n <FormField\n label={t('auth.passwordResetComplete.form.passwordLabel')}\n name=\"new-password\"\n type=\"password\"\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n setError(null);\n }}\n placeholder={t(\n 'auth.passwordResetComplete.form.passwordPlaceholder',\n )}\n autoComplete=\"new-password\"\n required\n />\n <FormField\n label={t('auth.passwordResetComplete.form.confirmLabel')}\n name=\"confirm-password\"\n type=\"password\"\n value={passwordConfirm}\n onChange={(event) => {\n setPasswordConfirm(event.target.value);\n setError(null);\n }}\n placeholder={t(\n 'auth.passwordResetComplete.form.confirmPlaceholder',\n )}\n autoComplete=\"new-password\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {t('auth.passwordResetComplete.form.submit')}\n </Button>\n </Form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.passwordResetComplete.title')}\n subtitle={t('auth.passwordResetComplete.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;AAmBA,IAAM,IAAsB,GAWf,KAA+B,EAC1C,kBACA,4BACA,eACwB;CACxB,IAAM,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAU,KAAe,EAAS,EAAE,GACrC,CAAC,GAAiB,KAAsB,EAAS,EAAE,GACnD,CAAC,GAAQ,KAAa,EAA+B,MAAM,GAC3D,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,CAAC,GAAc,KAAmB,EAAS,EAAK,GAEhD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAGF,IADY,gBAAgB,OAAO,SAAS,MAC5C,EAAO,IAAI,OAAO,KAAK,KAC7B,CAAC,CAAK,CAAC,GAEJ,IAAe,GAClB,MAAsC;EAIrC,IAHA,EAAM,eAAe,GACrB,EAAS,IAAI,GAET,MAAkB,IAAI;GACxB,EAAS,EAAE,gDAAgD,CAAC;GAC5D;EACF;EAEA,IAAI,EAAS,SAAS,GAAqB;GACzC,EACE,EAAE,+CAA+C,EAC/C,WAAW,EACb,CAAC,CACH;GACA;EACF;EAEA,IAAI,MAAa,GAAiB;GAChC,EAAS,EAAE,4CAA4C,CAAC;GACxD;EACF;EA0BA,AAxBA,EAAgB,EAAI,IAwBpB,YAtByD;GACvD,IAAI;IAKF,AAAI,MAJkB,EAAwB;KAC5C,aAAa;KACb,OAAO;IACT,CAAC,IAEC,EAAU,WAAW,IAErB,EAAS,EAAE,2CAA2C,CAAC;GAE3D,SAAS,GAAe;IACtB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,2CAA2C,CACnD;GACF,UAAU;IACR,EAAgB,EAAK;GACvB;EACF,GAEsB,EAAE,YAAY,CAEpC,CAAC;CACH,GACA;EAAC;EAAyB;EAAU;EAAiB;EAAe;CAAC,CACvE,GAEI;CAyEJ,OAxEA,AAsBE,IAtBE,MAAW,cAEX,kBAAC,GAAD;EACE,OAAO,EAAE,0CAA0C;EACnD,aAAa,EAAE,gDAAgD;EAC/D,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,WAAW;GACX,SAAS;aAER,EAAE,2CAA2C;EACxC,CAAA;YAGV,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,2CAA2C;EAC7C,CAAA;CACM,CAAA,IAIX,kBAAC,GAAD;EACE,OAAO,EAAE,uCAAuC;EAChD,aAAa,EAAE,6CAA6C;YAE5D,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;aAJf;IAMG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,EAAiB,CAAA;IAC9C,kBAAC,GAAD;KACE,OAAO,EAAE,+CAA+C;KACxD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAY,EAAM,OAAO,KAAK,GAC9B,EAAS,IAAI;KACf;KACA,aAAa,EACX,qDACF;KACA,cAAa;KACb,UAAA;IACD,CAAA;IACD,kBAAC,GAAD;KACE,OAAO,EAAE,8CAA8C;KACvD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAmB,EAAM,OAAO,KAAK,GACrC,EAAS,IAAI;KACf;KACA,aAAa,EACX,oDACF;KACA,cAAa;KACb,UAAA;IACD,CAAA;IACD,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,wCAAwC;IACrC,CAAA;GACJ;;CACG,CAAA,GAKb,kBAAC,GAAD;EACE,OAAO,EAAE,kCAAkC;EAC3C,UAAU,EAAE,qCAAqC;YAEhD;CACS,CAAA;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordResetRequestScreen.js","names":[],"sources":["../../../../src/auth/pages/PasswordResetRequestScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport * as styles from '../login/loginPage.css.js';\nimport AuthPanel from '../login/AuthPanel.js';\n\ntype Props = {\n onStartPasswordReset: (input: {\n email: string;\n locale?: string;\n }) => Promise<boolean>;\n};\n\nexport const PasswordResetRequestScreen = ({\n onStartPasswordReset,\n}: Props): JSX.Element => {\n const { i18n, t } = useBackofficeReactTranslation();\n const [email, setEmail] = useState('');\n const [status, setStatus] = useState<'idle' | 'sent'>('idle');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const locale = useMemo(() => {\n const language = i18n.language.trim();\n if (language !== '') {\n return language;\n }\n if (typeof navigator === 'undefined') {\n return undefined;\n }\n return navigator.language;\n }, [i18n.language]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (email.trim() === '') {\n setError(t('auth.passwordResetRequest.errors.emailRequired'));\n return;\n }\n\n setIsSubmitting(true);\n onStartPasswordReset({\n email: email.trim(),\n locale,\n })\n .then((success) => {\n if (success) {\n setStatus('sent');\n } else {\n setError(t('auth.passwordResetRequest.errors.startFailed'));\n }\n })\n .catch((mutationError) => {\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.passwordResetRequest.errors.startFailed'),\n );\n })\n .finally(() => {\n setIsSubmitting(false);\n });\n },\n [email, locale, onStartPasswordReset, t],\n );\n\n let content: JSX.Element;\n if (status === 'sent') {\n content = (\n <AuthPanel\n title={t('auth.passwordResetRequest.sent.title')}\n description={t('auth.passwordResetRequest.sent.description', { email })}\n footer={\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n setStatus('idle');\n }}\n >\n {t('auth.passwordResetRequest.sent.action')}\n </Button>\n }\n >\n <p className={styles.helper}>\n {t('auth.passwordResetRequest.sent.helper')}\n </p>\n </AuthPanel>\n );\n } else {\n content = (\n <AuthPanel description={t('auth.passwordResetRequest.form.description')}>\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n noValidate\n initialFocus=\"first-form-control\"\n >\n {error != null ? <FormError>{error}</FormError> : null}\n <FormField\n label={t('auth.passwordResetRequest.form.emailLabel')}\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n setError(null);\n }}\n placeholder={t('auth.passwordResetRequest.form.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {t('auth.passwordResetRequest.form.submit')}\n </Button>\n </Form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout title={t('auth.passwordResetRequest.title')}>\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;AA0BA,IAAa,KAA8B,EACzC,8BACwB;CACxB,IAAM,EAAE,SAAM,SAAM,GAA+B,EAC7C,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,CAAC,GAAQ,KAAa,EAA0B,OAAO,EACvD,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAS,QAAc;EAC3B,IAAM,IAAW,EAAK,SAAS,MAAM;EACrC,IAAI,MAAa,IACf,OAAO;EAEL,aAAO,YAAc,MAGzB,OAAO,UAAU;IAChB,CAAC,EAAK,SAAS,CAAC,EAEb,IAAe,GAClB,MAAsC;EAIrC,IAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,EAAM,MAAM,KAAK,IAAI;GACvB,EAAS,EAAE,iDAAiD,CAAC;GAC7D;;EAIF,AADA,EAAgB,GAAK,EACrB,EAAqB;GACnB,OAAO,EAAM,MAAM;GACnB;GACD,CAAC,CACC,MAAM,MAAY;GACjB,AAAI,IACF,EAAU,OAAO,GAEjB,EAAS,EAAE,+CAA+C,CAAC;IAE7D,CACD,OAAO,MAAkB;GACxB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,+CAA+C,CACtD;IACD,CACD,cAAc;GACb,EAAgB,GAAM;IACtB;IAEN;EAAC;EAAO;EAAQ;EAAsB;EAAE,CACzC,EAEG;CAsDJ,OArDA,AAuBE,IAvBE,MAAW,SAEX,kBAAC,GAAD;EACE,OAAO,EAAE,uCAAuC;EAChD,aAAa,EAAE,8CAA8C,EAAE,UAAO,CAAC;EACvE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,eAAe;IACb,EAAU,OAAO;;aAGlB,EAAE,wCAAwC;GACpC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,wCAAwC;GACzC,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EAAW,aAAa,EAAE,6CAA6C;YACrE,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;aAJf;IAMG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,4CAA4C;KACrD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAS,EAAM,OAAO,MAAM,EAC5B,EAAS,KAAK;;KAEhB,aAAa,EAAE,kDAAkD;KACjE,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,wCAAwC;KACpC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EAAY,OAAO,EAAE,kCAAkC;YACpD;EACU,CAAA"}
1
+ {"version":3,"file":"PasswordResetRequestScreen.js","names":[],"sources":["../../../../src/auth/pages/PasswordResetRequestScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { FormField } from '@plumile/ui/atomic/molecules/form_field/FormField.js';\nimport { Form } from '@plumile/ui/atomic/molecules/form/Form.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport * as styles from '../login/loginPage.css.js';\nimport AuthPanel from '../login/AuthPanel.js';\n\ntype Props = {\n onStartPasswordReset: (input: {\n email: string;\n locale?: string;\n }) => Promise<boolean>;\n};\n\nexport const PasswordResetRequestScreen = ({\n onStartPasswordReset,\n}: Props): JSX.Element => {\n const { i18n, t } = useBackofficeReactTranslation();\n const [email, setEmail] = useState('');\n const [status, setStatus] = useState<'idle' | 'sent'>('idle');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const locale = useMemo(() => {\n const language = i18n.language.trim();\n if (language !== '') {\n return language;\n }\n if (typeof navigator === 'undefined') {\n return undefined;\n }\n return navigator.language;\n }, [i18n.language]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (email.trim() === '') {\n setError(t('auth.passwordResetRequest.errors.emailRequired'));\n return;\n }\n\n setIsSubmitting(true);\n onStartPasswordReset({\n email: email.trim(),\n locale,\n })\n .then((success) => {\n if (success) {\n setStatus('sent');\n } else {\n setError(t('auth.passwordResetRequest.errors.startFailed'));\n }\n })\n .catch((mutationError) => {\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.passwordResetRequest.errors.startFailed'),\n );\n })\n .finally(() => {\n setIsSubmitting(false);\n });\n },\n [email, locale, onStartPasswordReset, t],\n );\n\n let content: JSX.Element;\n if (status === 'sent') {\n content = (\n <AuthPanel\n title={t('auth.passwordResetRequest.sent.title')}\n description={t('auth.passwordResetRequest.sent.description', { email })}\n footer={\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n setStatus('idle');\n }}\n >\n {t('auth.passwordResetRequest.sent.action')}\n </Button>\n }\n >\n <p className={styles.helper}>\n {t('auth.passwordResetRequest.sent.helper')}\n </p>\n </AuthPanel>\n );\n } else {\n content = (\n <AuthPanel description={t('auth.passwordResetRequest.form.description')}>\n <Form\n className={styles.formSurface}\n onSubmit={handleSubmit}\n noValidate\n initialFocus=\"first-form-control\"\n >\n {error != null ? <FormError>{error}</FormError> : null}\n <FormField\n label={t('auth.passwordResetRequest.form.emailLabel')}\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n setError(null);\n }}\n placeholder={t('auth.passwordResetRequest.form.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {t('auth.passwordResetRequest.form.submit')}\n </Button>\n </Form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout title={t('auth.passwordResetRequest.title')}>\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;AA0BA,IAAa,KAA8B,EACzC,8BACwB;CACxB,IAAM,EAAE,SAAM,SAAM,EAA8B,GAC5C,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAQ,KAAa,EAA0B,MAAM,GACtD,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,CAAC,GAAc,KAAmB,EAAS,EAAK,GAEhD,IAAS,QAAc;EAC3B,IAAM,IAAW,EAAK,SAAS,KAAK;EACpC,IAAI,MAAa,IACf,OAAO;EAEL,aAAO,YAAc,MAGzB,OAAO,UAAU;CACnB,GAAG,CAAC,EAAK,QAAQ,CAAC,GAEZ,IAAe,GAClB,MAAsC;EAIrC,IAHA,EAAM,eAAe,GACrB,EAAS,IAAI,GAET,EAAM,KAAK,MAAM,IAAI;GACvB,EAAS,EAAE,gDAAgD,CAAC;GAC5D;EACF;EAGA,AADA,EAAgB,EAAI,GACpB,EAAqB;GACnB,OAAO,EAAM,KAAK;GAClB;EACF,CAAC,EACE,MAAM,MAAY;GACjB,AAAI,IACF,EAAU,MAAM,IAEhB,EAAS,EAAE,8CAA8C,CAAC;EAE9D,CAAC,EACA,OAAO,MAAkB;GACxB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,8CAA8C,CACtD;EACF,CAAC,EACA,cAAc;GACb,EAAgB,EAAK;EACvB,CAAC;CACL,GACA;EAAC;EAAO;EAAQ;EAAsB;CAAC,CACzC,GAEI;CAsDJ,OArDA,AAuBE,IAvBE,MAAW,SAEX,kBAAC,GAAD;EACE,OAAO,EAAE,sCAAsC;EAC/C,aAAa,EAAE,8CAA8C,EAAE,SAAM,CAAC;EACtE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,eAAe;IACb,EAAU,MAAM;GAClB;aAEC,EAAE,uCAAuC;EACpC,CAAA;YAGV,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,uCAAuC;EACzC,CAAA;CACM,CAAA,IAIX,kBAAC,GAAD;EAAW,aAAa,EAAE,4CAA4C;YACpE,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;aAJf;IAMG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,EAAiB,CAAA;IAC9C,kBAAC,GAAD;KACE,OAAO,EAAE,2CAA2C;KACpD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;MAEnB,AADA,EAAS,EAAM,OAAO,KAAK,GAC3B,EAAS,IAAI;KACf;KACA,aAAa,EAAE,iDAAiD;KAChE,cAAa;KACb,UAAA;IACD,CAAA;IACD,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,uCAAuC;IACpC,CAAA;GACJ;;CACG,CAAA,GAKb,kBAAC,GAAD;EAAY,OAAO,EAAE,iCAAiC;YACnD;CACS,CAAA;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"VerifyEmailScreen.js","names":[],"sources":["../../../../src/auth/pages/VerifyEmailScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { useEffect, useMemo, useState, type JSX } from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport * as styles from '../login/loginPage.css.js';\n\ntype VerificationState = 'pending' | 'success' | 'error';\n\ntype Props = {\n onBackToLogin: () => void;\n onVerifyEmail: (input: { token: string }) => Promise<boolean>;\n token?: string;\n};\n\nexport const VerifyEmailScreen = ({\n onBackToLogin,\n onVerifyEmail,\n token,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [state, setState] = useState<VerificationState>('pending');\n const [error, setError] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n useEffect(() => {\n if (resolvedToken === '') {\n setState('error');\n setError(t('auth.verifyEmail.errors.missingToken'));\n return;\n }\n\n const verifyEmail = async (): Promise<void> => {\n try {\n const success = await onVerifyEmail({ token: resolvedToken });\n if (success) {\n setState('success');\n } else {\n setState('error');\n setError(t('auth.verifyEmail.errors.invalid'));\n }\n } catch (mutationError) {\n setState('error');\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.verifyEmail.errors.invalid'),\n );\n }\n };\n\n verifyEmail().catch(() => {\n return undefined;\n });\n }, [onVerifyEmail, resolvedToken, t]);\n\n let content: JSX.Element;\n if (state === 'success') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.verifyEmail.status.success')}</p>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.continue')}\n </Button>\n </div>\n );\n } else if (state === 'error') {\n content = (\n <div className={styles.stack}>\n {error != null ? <FormError>{error}</FormError> : null}\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.return')}\n </Button>\n </div>\n );\n } else {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.verifyEmail.status.verifying')}\n </p>\n <Button type=\"button\" isLoading>\n {t('auth.verifyEmail.status.verifyingButton')}\n </Button>\n </div>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.verifyEmail.title')}\n subtitle={t('auth.verifyEmail.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;;;AAkBA,IAAa,KAAqB,EAChC,kBACA,kBACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAA+B,EACvC,CAAC,GAAO,KAAY,EAA4B,UAAU,EAC1D,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAGF,IADY,gBAAgB,OAAO,SAAS,OAC5C,CAAO,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC;CAEX,QAAgB;EACd,IAAI,MAAkB,IAAI;GAExB,AADA,EAAS,QAAQ,EACjB,EAAS,EAAE,uCAAuC,CAAC;GACnD;;EAsBF,aAnB+C;GAC7C,IAAI;IAEF,AAAI,MADkB,EAAc,EAAE,OAAO,GAAe,CAAC,GAE3D,EAAS,UAAU,IAEnB,EAAS,QAAQ,EACjB,EAAS,EAAE,kCAAkC,CAAC;YAEzC,GAAe;IAEtB,AADA,EAAS,QAAQ,EACjB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,kCAAkC,CACzC;;MAIQ,CAAC,YAAY,GAExB;IACD;EAAC;EAAe;EAAe;EAAE,CAAC;CAErC,IAAI;CAgCJ,OA/BA,AAmBE,IAnBE,MAAU,YAEV,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aAAgB,EAAE,kCAAkC;GAAK,CAAA,EACvE,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,oCAAoC;GAChC,CAAA,CACL;MAEC,MAAU,UAEjB,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA,EAC/C,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,kCAAkC;GAC9B,CAAA,CACL;MAIN,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,oCAAoC;GACrC,CAAA,EACJ,kBAAC,GAAD;GAAQ,MAAK;GAAS,WAAA;aACnB,EAAE,0CAA0C;GACtC,CAAA,CACL;KAKR,kBAAC,GAAD;EACE,OAAO,EAAE,yBAAyB;EAClC,UAAU,EAAE,4BAA4B;YAEvC;EACU,CAAA"}
1
+ {"version":3,"file":"VerifyEmailScreen.js","names":[],"sources":["../../../../src/auth/pages/VerifyEmailScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { useEffect, useMemo, useState, type JSX } from 'react';\nimport { useBackofficeReactTranslation } from '../../i18n/useBackofficeReactTranslation.js';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { FormError } from '@plumile/ui/atomic/molecules/form_error/FormError.js';\nimport { AuthLayout } from '@plumile/ui/atomic/templates/auth_layout/AuthLayout.js';\n\nimport * as styles from '../login/loginPage.css.js';\n\ntype VerificationState = 'pending' | 'success' | 'error';\n\ntype Props = {\n onBackToLogin: () => void;\n onVerifyEmail: (input: { token: string }) => Promise<boolean>;\n token?: string;\n};\n\nexport const VerifyEmailScreen = ({\n onBackToLogin,\n onVerifyEmail,\n token,\n}: Props): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [state, setState] = useState<VerificationState>('pending');\n const [error, setError] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n useEffect(() => {\n if (resolvedToken === '') {\n setState('error');\n setError(t('auth.verifyEmail.errors.missingToken'));\n return;\n }\n\n const verifyEmail = async (): Promise<void> => {\n try {\n const success = await onVerifyEmail({ token: resolvedToken });\n if (success) {\n setState('success');\n } else {\n setState('error');\n setError(t('auth.verifyEmail.errors.invalid'));\n }\n } catch (mutationError) {\n setState('error');\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.verifyEmail.errors.invalid'),\n );\n }\n };\n\n verifyEmail().catch(() => {\n return undefined;\n });\n }, [onVerifyEmail, resolvedToken, t]);\n\n let content: JSX.Element;\n if (state === 'success') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.verifyEmail.status.success')}</p>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.continue')}\n </Button>\n </div>\n );\n } else if (state === 'error') {\n content = (\n <div className={styles.stack}>\n {error != null ? <FormError>{error}</FormError> : null}\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.return')}\n </Button>\n </div>\n );\n } else {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.verifyEmail.status.verifying')}\n </p>\n <Button type=\"button\" isLoading>\n {t('auth.verifyEmail.status.verifyingButton')}\n </Button>\n </div>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.verifyEmail.title')}\n subtitle={t('auth.verifyEmail.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;;;AAkBA,IAAa,KAAqB,EAChC,kBACA,kBACA,eACwB;CACxB,IAAM,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAO,KAAY,EAA4B,SAAS,GACzD,CAAC,GAAO,KAAY,EAAwB,IAAI,GAEhD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAGF,IADY,gBAAgB,OAAO,SAAS,MAC5C,EAAO,IAAI,OAAO,KAAK,KAC7B,CAAC,CAAK,CAAC;CAEV,QAAgB;EACd,IAAI,MAAkB,IAAI;GAExB,AADA,EAAS,OAAO,GAChB,EAAS,EAAE,sCAAsC,CAAC;GAClD;EACF;EAqBA,aAnB+C;GAC7C,IAAI;IAEF,AAAI,MADkB,EAAc,EAAE,OAAO,EAAc,CAAC,IAE1D,EAAS,SAAS,KAElB,EAAS,OAAO,GAChB,EAAS,EAAE,iCAAiC,CAAC;GAEjD,SAAS,GAAe;IAEtB,AADA,EAAS,OAAO,GAChB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,iCAAiC,CACzC;GACF;EACF,GAEY,EAAE,YAAY,CAE1B,CAAC;CACH,GAAG;EAAC;EAAe;EAAe;CAAC,CAAC;CAEpC,IAAI;CAgCJ,OA/BA,AAmBE,IAnBE,MAAU,YAEV,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aAAgB,EAAE,iCAAiC;EAAK,CAAA,GACtE,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,mCAAmC;EAChC,CAAA,CACL;MAEE,MAAU,UAEjB,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,EAAiB,CAAA,GAC9C,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,iCAAiC;EAC9B,CAAA,CACL;MAIL,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,mCAAmC;EACrC,CAAA,GACH,kBAAC,GAAD;GAAQ,MAAK;GAAS,WAAA;aACnB,EAAE,yCAAyC;EACtC,CAAA,CACL;KAKP,kBAAC,GAAD;EACE,OAAO,EAAE,wBAAwB;EACjC,UAAU,EAAE,2BAA2B;YAEtC;CACS,CAAA;AAEhB"}
@@ -341,7 +341,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
341
341
  }),
342
342
  n != null && /* @__PURE__ */ g("span", {
343
343
  id: a,
344
- className: "txvbqb96 txvbqb19bn",
344
+ className: "txvbqb96 txvbqb1bff",
345
345
  children: n
346
346
  }),
347
347
  /* @__PURE__ */ g(y, {
@@ -360,7 +360,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
360
360
  }),
361
361
  s != null && /* @__PURE__ */ g("span", {
362
362
  id: o,
363
- className: "txvbqb96 txvbqb19cn",
363
+ className: "txvbqb96 txvbqb1bij",
364
364
  children: s
365
365
  })
366
366
  ] }, e.id);
@@ -377,7 +377,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
377
377
  }),
378
378
  n != null && /* @__PURE__ */ g("span", {
379
379
  id: a,
380
- className: "txvbqb96 txvbqb19bn",
380
+ className: "txvbqb96 txvbqb1bff",
381
381
  children: n
382
382
  }),
383
383
  /* @__PURE__ */ g(y, {
@@ -396,7 +396,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
396
396
  }),
397
397
  s != null && /* @__PURE__ */ g("span", {
398
398
  id: o,
399
- className: "txvbqb96 txvbqb19cn",
399
+ className: "txvbqb96 txvbqb1bij",
400
400
  children: s
401
401
  })
402
402
  ] }, e.id);
@@ -413,7 +413,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
413
413
  }),
414
414
  n != null && /* @__PURE__ */ g("span", {
415
415
  id: a,
416
- className: "txvbqb96 txvbqb19bn",
416
+ className: "txvbqb96 txvbqb1bff",
417
417
  children: n
418
418
  }),
419
419
  /* @__PURE__ */ g(ce, {
@@ -432,7 +432,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
432
432
  }),
433
433
  s != null && /* @__PURE__ */ g("span", {
434
434
  id: o,
435
- className: "txvbqb96 txvbqb19cn",
435
+ className: "txvbqb96 txvbqb1bij",
436
436
  children: s
437
437
  })
438
438
  ] }, e.id);
@@ -453,7 +453,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
453
453
  }),
454
454
  n != null && /* @__PURE__ */ g("span", {
455
455
  id: a,
456
- className: "txvbqb96 txvbqb19bn",
456
+ className: "txvbqb96 txvbqb1bff",
457
457
  children: n
458
458
  }),
459
459
  /* @__PURE__ */ g(fe, {
@@ -471,7 +471,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
471
471
  }),
472
472
  s != null && /* @__PURE__ */ g("span", {
473
473
  id: o,
474
- className: "txvbqb96 txvbqb19cn",
474
+ className: "txvbqb96 txvbqb1bij",
475
475
  children: s
476
476
  })
477
477
  ] }, e.id);
@@ -500,7 +500,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
500
500
  }),
501
501
  n != null && /* @__PURE__ */ g("span", {
502
502
  id: a,
503
- className: "txvbqb96 txvbqb19bn",
503
+ className: "txvbqb96 txvbqb1bff",
504
504
  children: n
505
505
  }),
506
506
  /* @__PURE__ */ g(r, {
@@ -523,7 +523,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
523
523
  }),
524
524
  s != null && /* @__PURE__ */ g("span", {
525
525
  id: o,
526
- className: "txvbqb96 txvbqb19cn",
526
+ className: "txvbqb96 txvbqb1bij",
527
527
  children: s
528
528
  })
529
529
  ] }, e.id);
@@ -537,13 +537,13 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
537
537
  id: d,
538
538
  className: ee,
539
539
  children: [t, e.required && /* @__PURE__ */ g("span", {
540
- className: "txvbqbo4z txvbqb19cn",
540
+ className: "txvbqbq3e txvbqb1bij",
541
541
  children: "*"
542
542
  })]
543
543
  }),
544
544
  n != null && /* @__PURE__ */ g("span", {
545
545
  id: a,
546
- className: "txvbqb96 txvbqb19bn",
546
+ className: "txvbqb96 txvbqb1bff",
547
547
  children: n
548
548
  }),
549
549
  /* @__PURE__ */ g("div", {
@@ -569,7 +569,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
569
569
  ]
570
570
  }), s != null && /* @__PURE__ */ g("span", {
571
571
  id: o,
572
- className: "txvbqb96 txvbqb19cn",
572
+ className: "txvbqb96 txvbqb1bij",
573
573
  children: s
574
574
  })] }, e.id);
575
575
  }
@@ -577,7 +577,7 @@ var { commitMutation: me, useRelayEnvironment: he } = v, C = (e, t) => e(t), w =
577
577
  }
578
578
  }) }),
579
579
  $ && /* @__PURE__ */ _("div", {
580
- className: "txvbqbdr8 txvbqbf6i txvbqbff6",
580
+ className: "txvbqbfpn txvbqbh4x txvbqbhdl",
581
581
  children: [V != null && Q != null && /* @__PURE__ */ g(le, {
582
582
  badgeLabel: Q,
583
583
  copyCode: V,