@plumile/backoffice-react 0.1.201 → 0.1.205

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 (167) hide show
  1. package/README.md +4 -4
  2. package/lib/esm/auth/login/LoginFlow.js.map +1 -1
  3. package/lib/esm/auth/pages/AcceptInvitationScreen.js.map +1 -1
  4. package/lib/esm/auth/pages/PasswordResetCompleteScreen.js.map +1 -1
  5. package/lib/esm/auth/pages/PasswordResetRequestScreen.js.map +1 -1
  6. package/lib/esm/components/backoffice/detail/BackofficeEntitySummaryHeader.js +28 -28
  7. package/lib/esm/components/backoffice/detail/BackofficeEntitySummaryHeader.js.map +1 -1
  8. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js +183 -183
  9. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
  10. package/lib/esm/hooks/useAuth.js +56 -56
  11. package/lib/esm/hooks/useAuth.js.map +1 -1
  12. package/lib/esm/hooks/useConditionalSubscription.js +18 -18
  13. package/lib/esm/hooks/useConditionalSubscription.js.map +1 -1
  14. package/lib/esm/index.js +49 -57
  15. package/lib/esm/pages/BackofficeEntityDetailPage.js +97 -97
  16. package/lib/esm/pages/BackofficeEntityDetailPage.js.map +1 -1
  17. package/lib/esm/pages/BackofficeLayoutPage.js +19 -19
  18. package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
  19. package/lib/esm/provider/BackofficeProvider.js +33 -33
  20. package/lib/esm/router/createBackofficeRoutes.js +26 -28
  21. package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
  22. package/lib/esm/storybook/relay/RelayStory.js +32 -32
  23. package/lib/esm/storybook/relay/RelayStory.js.map +1 -1
  24. package/lib/esm/storybook/relay/mockResolvers.js.map +1 -1
  25. package/lib/esm/style.css +1 -1
  26. package/lib/types/components/backoffice/detail/BackofficeEntitySummaryHeader.d.ts +1 -1
  27. package/lib/types/components/backoffice/detail/BackofficeEntitySummaryHeader.d.ts.map +1 -1
  28. package/lib/types/hooks/useAuth.d.ts.map +1 -1
  29. package/lib/types/hooks/useConditionalSubscription.d.ts.map +1 -1
  30. package/lib/types/i18n/locales/en/backofficeReact.d.ts +5 -0
  31. package/lib/types/i18n/locales/fr/backofficeReact.d.ts +5 -0
  32. package/lib/types/index.d.ts +1 -9
  33. package/lib/types/index.d.ts.map +1 -1
  34. package/lib/types/pages/BackofficeLayoutPage.d.ts.map +1 -1
  35. package/lib/types/router/createBackofficeRoutes.d.ts +3 -3
  36. package/lib/types/router/createBackofficeRoutes.d.ts.map +1 -1
  37. package/lib/types/storybook/relay/RelayStory.d.ts +1 -1
  38. package/lib/types/storybook/relay/RelayStory.d.ts.map +1 -1
  39. package/lib/types/storybook/relay/mockResolvers.d.ts +9 -1
  40. package/lib/types/storybook/relay/mockResolvers.d.ts.map +1 -1
  41. package/package.json +12 -15
  42. package/lib/esm/_virtual/_rolldown/runtime.js +0 -7
  43. package/lib/esm/components/backoffice/detail/BackofficeDetailFlagTag.js +0 -13
  44. package/lib/esm/components/backoffice/detail/BackofficeDetailFlagTag.js.map +0 -1
  45. package/lib/esm/components/backoffice/detail/BackofficeDetailTaggedValue.js +0 -12
  46. package/lib/esm/components/backoffice/detail/BackofficeDetailTaggedValue.js.map +0 -1
  47. package/lib/esm/components/backoffice/detail/BackofficeEnumLabel.js +0 -16
  48. package/lib/esm/components/backoffice/detail/BackofficeEnumLabel.js.map +0 -1
  49. package/lib/esm/components/backoffice/detail/BackofficeReferenceValue.js +0 -17
  50. package/lib/esm/components/backoffice/detail/BackofficeReferenceValue.js.map +0 -1
  51. package/lib/esm/components/backoffice/detail/BackofficeStatusGroup.js +0 -8
  52. package/lib/esm/components/backoffice/detail/BackofficeStatusGroup.js.map +0 -1
  53. package/lib/esm/components/backoffice/detail/BackofficeStatusMetaBadge.js +0 -16
  54. package/lib/esm/components/backoffice/detail/BackofficeStatusMetaBadge.js.map +0 -1
  55. package/lib/esm/components/backoffice/detail/backofficeDetailRelationLink.css.js +0 -6
  56. package/lib/esm/components/backoffice/detail/backofficeDetailRelationLink.css.js.map +0 -1
  57. package/lib/esm/components/backoffice/refs/backofficeEntityIdRef.css.js +0 -6
  58. package/lib/esm/components/backoffice/refs/backofficeEntityIdRef.css.js.map +0 -1
  59. package/lib/esm/components/backoffice/routing/BackofficeRoutePendingBar.js +0 -12
  60. package/lib/esm/components/backoffice/routing/BackofficeRoutePendingBar.js.map +0 -1
  61. package/lib/esm/components/backoffice/routing/backofficeRoutePendingBar.css.js +0 -7
  62. package/lib/esm/components/backoffice/routing/backofficeRoutePendingBar.css.js.map +0 -1
  63. package/lib/esm/modules/base64.js +0 -21
  64. package/lib/esm/modules/base64.js.map +0 -1
  65. package/lib/esm/node_modules/@babel/runtime/helpers/arrayLikeToArray.js +0 -15
  66. package/lib/esm/node_modules/@babel/runtime/helpers/arrayLikeToArray.js.map +0 -1
  67. package/lib/esm/node_modules/@babel/runtime/helpers/arrayWithoutHoles.js +0 -15
  68. package/lib/esm/node_modules/@babel/runtime/helpers/arrayWithoutHoles.js.map +0 -1
  69. package/lib/esm/node_modules/@babel/runtime/helpers/defineProperty.js +0 -20
  70. package/lib/esm/node_modules/@babel/runtime/helpers/defineProperty.js.map +0 -1
  71. package/lib/esm/node_modules/@babel/runtime/helpers/interopRequireDefault.js +0 -13
  72. package/lib/esm/node_modules/@babel/runtime/helpers/interopRequireDefault.js.map +0 -1
  73. package/lib/esm/node_modules/@babel/runtime/helpers/iterableToArray.js +0 -13
  74. package/lib/esm/node_modules/@babel/runtime/helpers/iterableToArray.js.map +0 -1
  75. package/lib/esm/node_modules/@babel/runtime/helpers/nonIterableSpread.js +0 -13
  76. package/lib/esm/node_modules/@babel/runtime/helpers/nonIterableSpread.js.map +0 -1
  77. package/lib/esm/node_modules/@babel/runtime/helpers/objectSpread2.js +0 -33
  78. package/lib/esm/node_modules/@babel/runtime/helpers/objectSpread2.js.map +0 -1
  79. package/lib/esm/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js +0 -19
  80. package/lib/esm/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js.map +0 -1
  81. package/lib/esm/node_modules/@babel/runtime/helpers/toConsumableArray.js +0 -18
  82. package/lib/esm/node_modules/@babel/runtime/helpers/toConsumableArray.js.map +0 -1
  83. package/lib/esm/node_modules/@babel/runtime/helpers/toPrimitive.js +0 -22
  84. package/lib/esm/node_modules/@babel/runtime/helpers/toPrimitive.js.map +0 -1
  85. package/lib/esm/node_modules/@babel/runtime/helpers/toPropertyKey.js +0 -17
  86. package/lib/esm/node_modules/@babel/runtime/helpers/toPropertyKey.js.map +0 -1
  87. package/lib/esm/node_modules/@babel/runtime/helpers/typeof.js +0 -18
  88. package/lib/esm/node_modules/@babel/runtime/helpers/typeof.js.map +0 -1
  89. package/lib/esm/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js +0 -19
  90. package/lib/esm/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js.map +0 -1
  91. package/lib/esm/node_modules/fbjs/lib/areEqual.js +0 -42
  92. package/lib/esm/node_modules/fbjs/lib/areEqual.js.map +0 -1
  93. package/lib/esm/node_modules/invariant/browser.js +0 -30
  94. package/lib/esm/node_modules/invariant/browser.js.map +0 -1
  95. package/lib/esm/node_modules/relay-test-utils/index.js +0 -11
  96. package/lib/esm/node_modules/relay-test-utils/index.js.map +0 -1
  97. package/lib/esm/node_modules/relay-test-utils/lib/RelayMockPayloadGenerator.js +0 -288
  98. package/lib/esm/node_modules/relay-test-utils/lib/RelayMockPayloadGenerator.js.map +0 -1
  99. package/lib/esm/node_modules/relay-test-utils/lib/RelayModernMockEnvironment.js +0 -183
  100. package/lib/esm/node_modules/relay-test-utils/lib/RelayModernMockEnvironment.js.map +0 -1
  101. package/lib/esm/node_modules/relay-test-utils/lib/RelayResolverTestUtils.js +0 -19
  102. package/lib/esm/node_modules/relay-test-utils/lib/RelayResolverTestUtils.js.map +0 -1
  103. package/lib/esm/node_modules/relay-test-utils/lib/index.js +0 -21
  104. package/lib/esm/node_modules/relay-test-utils/lib/index.js.map +0 -1
  105. package/lib/esm/node_modules/relay-test-utils/lib/unwrapContainer.js +0 -16
  106. package/lib/esm/node_modules/relay-test-utils/lib/unwrapContainer.js.map +0 -1
  107. package/lib/esm/relay/RelayProvider.js +0 -2
  108. package/lib/esm/relay/envHelpers.js +0 -63
  109. package/lib/esm/relay/envHelpers.js.map +0 -1
  110. package/lib/esm/relay/environment.js +0 -2
  111. package/lib/esm/relay/shortAccessTokenEnvironment.js +0 -2
  112. package/lib/esm/relay/useRelayOperationActivity.js +0 -2
  113. package/lib/esm/storybook/relay/relay-test-utils.d.js +0 -0
  114. package/lib/types/auth/AuthFlows.stories.d.ts +0 -19
  115. package/lib/types/auth/AuthFlows.stories.d.ts.map +0 -1
  116. package/lib/types/components/backoffice/billing/BackofficeBillingUsageChart.stories.d.ts +0 -41
  117. package/lib/types/components/backoffice/billing/BackofficeBillingUsageChart.stories.d.ts.map +0 -1
  118. package/lib/types/components/backoffice/detail/BackofficeDetailFlagTag.d.ts +0 -11
  119. package/lib/types/components/backoffice/detail/BackofficeDetailFlagTag.d.ts.map +0 -1
  120. package/lib/types/components/backoffice/detail/BackofficeDetailPrimitives.stories.d.ts +0 -17
  121. package/lib/types/components/backoffice/detail/BackofficeDetailPrimitives.stories.d.ts.map +0 -1
  122. package/lib/types/components/backoffice/detail/BackofficeDetailTaggedValue.d.ts +0 -13
  123. package/lib/types/components/backoffice/detail/BackofficeDetailTaggedValue.d.ts.map +0 -1
  124. package/lib/types/components/backoffice/detail/BackofficeEnumLabel.d.ts +0 -9
  125. package/lib/types/components/backoffice/detail/BackofficeEnumLabel.d.ts.map +0 -1
  126. package/lib/types/components/backoffice/detail/BackofficeReferenceValue.d.ts +0 -10
  127. package/lib/types/components/backoffice/detail/BackofficeReferenceValue.d.ts.map +0 -1
  128. package/lib/types/components/backoffice/detail/BackofficeStatusGroup.d.ts +0 -8
  129. package/lib/types/components/backoffice/detail/BackofficeStatusGroup.d.ts.map +0 -1
  130. package/lib/types/components/backoffice/detail/BackofficeStatusMetaBadge.d.ts +0 -11
  131. package/lib/types/components/backoffice/detail/BackofficeStatusMetaBadge.d.ts.map +0 -1
  132. package/lib/types/components/backoffice/detail/backofficeDetailRelationLink.css.d.ts +0 -6
  133. package/lib/types/components/backoffice/detail/backofficeDetailRelationLink.css.d.ts.map +0 -1
  134. package/lib/types/components/backoffice/errors/BackofficeErrorBoundary.stories.d.ts +0 -12
  135. package/lib/types/components/backoffice/errors/BackofficeErrorBoundary.stories.d.ts.map +0 -1
  136. package/lib/types/components/backoffice/filters/EntityIdFilterField.stories.d.ts +0 -12
  137. package/lib/types/components/backoffice/filters/EntityIdFilterField.stories.d.ts.map +0 -1
  138. package/lib/types/components/backoffice/hub/BackofficeHubTemplate.stories.d.ts +0 -49
  139. package/lib/types/components/backoffice/hub/BackofficeHubTemplate.stories.d.ts.map +0 -1
  140. package/lib/types/components/backoffice/overview/BackofficeOverviewLayout.stories.d.ts +0 -11
  141. package/lib/types/components/backoffice/overview/BackofficeOverviewLayout.stories.d.ts.map +0 -1
  142. package/lib/types/components/backoffice/pickers/EntityIdPickerDialog.stories.d.ts +0 -12
  143. package/lib/types/components/backoffice/pickers/EntityIdPickerDialog.stories.d.ts.map +0 -1
  144. package/lib/types/components/backoffice/refs/backofficeEntityIdRef.css.d.ts +0 -2
  145. package/lib/types/components/backoffice/refs/backofficeEntityIdRef.css.d.ts.map +0 -1
  146. package/lib/types/components/backoffice/routing/BackofficeRoutePendingBar.d.ts +0 -4
  147. package/lib/types/components/backoffice/routing/BackofficeRoutePendingBar.d.ts.map +0 -1
  148. package/lib/types/components/backoffice/routing/backofficeRoutePendingBar.css.d.ts +0 -3
  149. package/lib/types/components/backoffice/routing/backofficeRoutePendingBar.css.d.ts.map +0 -1
  150. package/lib/types/components/backoffice/scaffolds/BackofficeTabbedDetailShell.stories.d.ts +0 -11
  151. package/lib/types/components/backoffice/scaffolds/BackofficeTabbedDetailShell.stories.d.ts.map +0 -1
  152. package/lib/types/components/backoffice/tools/BackofficeTools.stories.d.ts +0 -17
  153. package/lib/types/components/backoffice/tools/BackofficeTools.stories.d.ts.map +0 -1
  154. package/lib/types/modules/base64.d.ts +0 -3
  155. package/lib/types/modules/base64.d.ts.map +0 -1
  156. package/lib/types/pages/BackofficeDashboardPage.stories.d.ts +0 -9
  157. package/lib/types/pages/BackofficeDashboardPage.stories.d.ts.map +0 -1
  158. package/lib/types/relay/RelayProvider.d.ts +0 -2
  159. package/lib/types/relay/RelayProvider.d.ts.map +0 -1
  160. package/lib/types/relay/envHelpers.d.ts +0 -25
  161. package/lib/types/relay/envHelpers.d.ts.map +0 -1
  162. package/lib/types/relay/environment.d.ts +0 -2
  163. package/lib/types/relay/environment.d.ts.map +0 -1
  164. package/lib/types/relay/shortAccessTokenEnvironment.d.ts +0 -5
  165. package/lib/types/relay/shortAccessTokenEnvironment.d.ts.map +0 -1
  166. package/lib/types/relay/useRelayOperationActivity.d.ts +0 -2
  167. package/lib/types/relay/useRelayOperationActivity.d.ts.map +0 -1
package/README.md CHANGED
@@ -91,15 +91,15 @@ without loading the list facet.
91
91
 
92
92
  ### Relay and mutation helpers
93
93
 
94
- - `RelayProvider`
95
- - `configureRelayEnvironment`
96
- - `getEnvironment`
97
- - `resetRelayStore`
98
94
  - `resolveMutationOutcome`
99
95
  - `resolveAgentStartOutcome`
100
96
  - `requireField`
101
97
  - `requireLinkedRecordId`
102
98
 
99
+ Generic Relay environment, provider, transport, and operation-activity helpers
100
+ are owned by `@plumile/relay`. Import them from that package; this package keeps
101
+ only helpers tied to backoffice mutations, connections, and typed data.
102
+
103
103
  ### Backoffice-specific UI scaffolds
104
104
 
105
105
  - `BackofficeOverviewLayout`
@@ -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":";;;;;;;;;;;AAmCA,IAAa,KAAa,EACxB,SACA,kBACA,mBACA,0BACiC;CACjC,IAAM,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAS,KAAc,EAAgC,CAAC,CAAC,GAC1D,CAAC,GAAa,KAAkB,EAAwB,IAAI,GAC5D,CAAC,GAAM,KAAW,EAAe,OAAO,GACxC,CAAC,GAAiB,KAAsB,EAAS,EAAK,GACtD,CAAC,GAAY,KAAiB,EAAwB,IAAI,GAC1D,IAAuB,EAAO,EAAI,GAElC,IAAe,SACZ;EACL,GAAG;EACH,qBAAqB,OAAO,MAAuB;GACjD,IAAM,IAAS,MAAM,EAAK,oBAAoB,CAAU;GAIxD,OAHA,EAAS,CAAU,GACnB,EAAW,EAAO,OAAO,GACzB,EAAe,EAAO,WAAW,GAC1B;EACT;CACF,IACC,CAAC,CAAI,CAAC,GAEH,IAAqB,GACxB,EAAE,aAAU,EAAE,OAAO,GAAM,MAAM;EAC5B,CAAC,KAAS,EAAK,aAAa,UAGhC,EAAe;CACjB,GACA,CAAC,EAAK,UAAU,CAAc,CAChC,GAEM,IAAY,EAAK,aAAa,UAAU,MAAS,OACjD,IACF,EADU,IACR,6BACA,8BAA8B,GAC9B,IACF,EADa,IACX,gCACA,iCAAiC,GAEjC,IAAoB,EACxB,OAAO,MAAuB;EAC5B,EAAc,IAAI;EAClB,IAAI;GACF,IAAM,IAAU,EAAW,KAAK,GAC1B,IAAS,MAAM,EAAK,oBAAoB,CAAO;GAQrD,AAPA,EAAS,CAAO,GAChB,EAAW,EAAO,OAAO,GACzB,EAAe,EAAO,WAAW,GACd,EAAO,QAAQ,MAAM,MAC/B,MAAW,SAGhB,IACF,EAAQ,SAAS,IACR,EAAO,QAAQ,SAAS,UAAU,IAC3C,EAAQ,UAAU,IAElB,EAAQ,SAAS;EAErB,QAAQ;GACN,EAAc,EAAE,gCAAgC,CAAC;EACnD;CACF,GACA,CAAC,GAAM,CAAC,CACV;CAEA,QAAgB;EACd,EAAqB,UAAU;EAC/B,IAAM,IAAe,EAAM,KAAK;EA0ChC,OAxCE,MAAS,aAAa,CAAC,KAAmB,MAAiB,OAG3D,EAAmB,EAAI,IAgCvB,YA/BoC;GAClC,IAAI;IACF,IAAM,IAAS,MAAM,EAAa,iBAAiB,EACjD,OAAO,EACT,CAAC;IAED,IAAI,CAAC,EAAqB,SACxB;IAGF,IAAI,MAAW,WAAW;KACxB,EAAmB;KACnB;IACF;IAEA,IAAI,MAAW,gBAAgB;KAC7B,EAAQ,KAAK;KACb;IACF;IAGA,AADA,EAAQ,SAAS,GACjB,EAAc,EAAE,0CAA0C,CAAC;GAC7D,QAAQ;IACN,IAAI,CAAC,EAAqB,SACxB;IAIF,AADA,EAAc,EAAE,0CAA0C,CAAC,GAC3D,EAAQ,SAAS;GACnB;EACF,EACA,CAAgB,CAAC,CAAC,YAAY,CAE9B,CAAC,UAGU;GACX,EAAqB,UAAU;EACjC;CACF,GAAG;EAAC;EAAO;EAAoB;EAAiB;EAAc;EAAG;CAAI,CAAC;CAEtE,IAAI;CA4FJ,OA1FA,AAkEE,IAlEE,IAEA,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACQ;EACN,iBAAiB;GACf,EAAmB,EAAE,OAAO,GAAK,CAAC;EACpC;EACA,cAAc;GAEZ,AADA,EAAK,MAAM,GACX,EAAQ,OAAO;EACjB;CACD,CAAA,EACQ,CAAA,IAEJ,MAAS,YAEhB,kBAAC,GAAD;EACE,OAAO,EAAE,8BAA8B;EACvC,aAAa,EAAE,sCAAsC,EAAE,SAAM,CAAC;EAE9D,UAAA,kBAAC,GAAD;GACE,MAAM;GACN,WAAW;GACX,qBAAqB;IACnB,EAAQ,SAAS;GACnB;GACA,cAAc;GACd,qBAAqB,EAAK;EAC3B,CAAA;CACQ,CAAA,IAEJ,MAAS,YAEhB,kBAAC,GAAD;EAAW,OAAO,EAAE,8BAA8B;EAChD,UAAA,kBAAC,GAAD;GACS;GACE;GACI;GACb,WAAW,MAAW;IACpB,IAAI,MAAW,WAAW;KACxB,EAAQ,SAAS;KACjB;IACF;IACA,AAAI,MAAW,cACb,EAAQ,UAAU;GAEtB;GACA,cAAc;IACZ,EAAQ,OAAO;GACjB;EACD,CAAA;CACQ,CAAA,IAEJ,MAAS,aAEhB,kBAAC,GAAD;EACE,MAAM;EACN,cAAc;EACI;EAClB,WAAW;EACX,WAAW;CACZ,CAAA,IAKD,kBAAC,GAAD;EACS;EACP,cAAc;EACd,WAAW,EAAK;EAChB,gBAAgB,MAAU;GAExB,AADA,EAAS,CAAK,GACd,EAAc,IAAI;EACpB;EACA,kBAAkB;GAChB,IAAM,IAAU,EAAM,KAAK;GAC3B,IAAI,MAAY,IAAI;IAClB,EAAc,EAAE,qCAAqC,CAAC;IACtD;GACF;GACA,EAAkB,CAAO,CAAC,CAAC,YAAY,CAEvC,CAAC;EACH;EACkB;CACnB,CAAA,GAKH,kBAAC,GAAD;EAAmB;EAAiB;EACjC,UAAA;CACS,CAAA;AAEhB"}
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":"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,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,CAAA,CAAO,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,EAEA,CAAsB,CAAC,CAAC,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;GAER,UAAA,EAAE,2CAA2C;EACxC,CAAA;EAGV,UAAA,kBAAC,KAAD;GAAG,WAAW;GACX,UAAA,EAAE,2CAA2C;EAC7C,CAAA;CACM,CAAA,IAIX,kBAAC,GAAD;EACE,OAAO,EAAE,uCAAuC;EAChD,aAAa,EAAE,6CAA6C;EAE5D,UAAA,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;GAJf,UAAA;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;KAC9B,UAAA,EAAE,wCAAwC;IACrC,CAAA;GACJ;;CACG,CAAA,GAKb,kBAAC,GAAD;EACE,OAAO,EAAE,kCAAkC;EAC3C,UAAU,EAAE,qCAAqC;EAEhD,UAAA;CACS,CAAA;AAEhB"}
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,CAAA,CAAO,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,EAEA,CAAsB,CAAC,CAAC,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;GAER,UAAA,EAAE,2CAA2C;EACxC,CAAA;EAGV,UAAA,kBAAC,KAAD;GAAG,WAAW;GACX,UAAA,EAAE,2CAA2C;EAC7C,CAAA;CACM,CAAA,IAIX,kBAAC,GAAD;EACE,OAAO,EAAE,uCAAuC;EAChD,aAAa,EAAE,6CAA6C;EAE5D,UAAA,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;GAJf,UAAA;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;KAC9B,UAAA,EAAE,wCAAwC;IACrC,CAAA;GACJ;;CACG,CAAA,GAKb,kBAAC,GAAD;EACE,OAAO,EAAE,kCAAkC;EAC3C,UAAU,EAAE,qCAAqC;EAEhD,UAAA;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,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,CAAC,CACC,MAAM,MAAY;GACjB,AAAI,IACF,EAAU,MAAM,IAEhB,EAAS,EAAE,8CAA8C,CAAC;EAE9D,CAAC,CAAC,CACD,OAAO,MAAkB;GACxB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,8CAA8C,CACtD;EACF,CAAC,CAAC,CACD,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;GAEC,UAAA,EAAE,uCAAuC;EACpC,CAAA;EAGV,UAAA,kBAAC,KAAD;GAAG,WAAW;GACX,UAAA,EAAE,uCAAuC;EACzC,CAAA;CACM,CAAA,IAIX,kBAAC,GAAD;EAAW,aAAa,EAAE,4CAA4C;EACpE,UAAA,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;GAJf,UAAA;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;KAC9B,UAAA,EAAE,uCAAuC;IACpC,CAAA;GACJ;;CACG,CAAA,GAKb,kBAAC,GAAD;EAAY,OAAO,EAAE,iCAAiC;EACnD,UAAA;CACS,CAAA;AAEhB"}
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,CAAC,CACC,MAAM,MAAY;GACjB,AAAI,IACF,EAAU,MAAM,IAEhB,EAAS,EAAE,8CAA8C,CAAC;EAE9D,CAAC,CAAC,CACD,OAAO,MAAkB;GACxB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,8CAA8C,CACtD;EACF,CAAC,CAAC,CACD,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;GAEC,UAAA,EAAE,uCAAuC;EACpC,CAAA;EAGV,UAAA,kBAAC,KAAD;GAAG,WAAW;GACX,UAAA,EAAE,uCAAuC;EACzC,CAAA;CACM,CAAA,IAIX,kBAAC,GAAD;EAAW,aAAa,EAAE,4CAA4C;EACpE,UAAA,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,YAAA;GACA,cAAa;GAJf,UAAA;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;KAC9B,UAAA,EAAE,uCAAuC;IACpC,CAAA;GACJ;;CACG,CAAA,GAKb,kBAAC,GAAD;EAAY,OAAO,EAAE,iCAAiC;EACnD,UAAA;CACS,CAAA;AAEhB"}
@@ -1,12 +1,12 @@
1
1
  import { useBackofficeReactTranslation as e } from "../../../i18n/useBackofficeReactTranslation.js";
2
- import { BackofficeStatusMetaBadge as t } from "./BackofficeStatusMetaBadge.js";
3
- import { identity as n, root as r, title as i, titleRow as a, top as o } from "./backofficeEntitySummaryHeader.css.js";
4
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
5
- import { Button as l } from "@plumile/ui/atomic/atoms/button/Button.js";
6
- import { Tag as u } from "@plumile/ui/backoffice/atoms/tag/Tag.js";
7
- import { CopyableText as d } from "@plumile/ui/backoffice/atoms/copyable_text/CopyableText.js";
2
+ import { identity as t, root as n, title as r, titleRow as i, top as a } from "./backofficeEntitySummaryHeader.css.js";
3
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
4
+ import { Button as c } from "@plumile/ui/atomic/atoms/button/Button.js";
5
+ import { Tag as l } from "@plumile/ui/backoffice/atoms/tag/Tag.js";
6
+ import { CopyableText as u } from "@plumile/ui/backoffice/atoms/copyable_text/CopyableText.js";
7
+ import { BackofficeStatusMetaBadge as d } from "@plumile/ui/backoffice/molecules/backoffice_status_meta_badge/BackofficeStatusMetaBadge.js";
8
8
  //#region src/components/backoffice/detail/BackofficeEntitySummaryHeader.tsx
9
- var f = (e) => e === "danger" ? "danger" : e === "neutral" ? "secondary" : "primary", p = (e) => /* @__PURE__ */ s(l, {
9
+ var f = (e) => e === "danger" ? "danger" : e === "neutral" ? "secondary" : "primary", p = (e) => /* @__PURE__ */ o(c, {
10
10
  type: "button",
11
11
  variant: f(e.tone),
12
12
  size: "small",
@@ -15,51 +15,51 @@ var f = (e) => e === "danger" ? "danger" : e === "neutral" ? "secondary" : "prim
15
15
  isLoading: e.loading,
16
16
  onClick: e.onPress,
17
17
  children: e.label
18
- }, e.id), m = ({ title: l, entityLabel: f, subtitle: m, status: h, meta: g, primaryActions: _, secondaryActions: v }) => {
18
+ }, e.id), m = ({ title: c, entityLabel: f, subtitle: m, status: h, meta: g, primaryActions: _, secondaryActions: v }) => {
19
19
  let { t: y } = e(), b = [..._ ?? [], ...v ?? []];
20
- return /* @__PURE__ */ c("header", {
21
- className: r,
22
- children: [/* @__PURE__ */ c("div", {
23
- className: o,
24
- children: [/* @__PURE__ */ c("div", {
25
- className: n,
26
- children: [/* @__PURE__ */ c("div", {
27
- className: a,
20
+ return /* @__PURE__ */ s("header", {
21
+ className: n,
22
+ children: [/* @__PURE__ */ s("div", {
23
+ className: a,
24
+ children: [/* @__PURE__ */ s("div", {
25
+ className: t,
26
+ children: [/* @__PURE__ */ s("div", {
27
+ className: i,
28
28
  children: [
29
- /* @__PURE__ */ s("h1", {
30
- className: i,
31
- children: l
29
+ /* @__PURE__ */ o("h1", {
30
+ className: r,
31
+ children: c
32
32
  }),
33
- /* @__PURE__ */ s(u, {
33
+ /* @__PURE__ */ o(l, {
34
34
  tone: "neutral",
35
35
  children: f
36
36
  }),
37
- h != null && /* @__PURE__ */ s(t, { status: h })
37
+ h != null && /* @__PURE__ */ o(d, { status: h })
38
38
  ]
39
- }), m != null && /* @__PURE__ */ s("div", {
39
+ }), m != null && /* @__PURE__ */ o("div", {
40
40
  className: "txvbqb9j txvbqb1bgt txvbqbws9",
41
41
  children: m
42
42
  })]
43
- }), b.length > 0 && /* @__PURE__ */ s("div", {
43
+ }), b.length > 0 && /* @__PURE__ */ o("div", {
44
44
  className: "txvbqbfpn txvbqbey txvbqblsh txvbqbhdl txvbqbh7g",
45
45
  children: b.map(p)
46
46
  })]
47
- }), g != null && g.length > 0 && /* @__PURE__ */ s("div", {
47
+ }), g != null && g.length > 0 && /* @__PURE__ */ o("div", {
48
48
  className: "txvbqbfq0 txvbqbhdy txvbqbjcq",
49
49
  children: g.map((e) => {
50
50
  let t = e.value;
51
- return e.copyValue != null && e.copyValue !== "" && (t = /* @__PURE__ */ s(d, {
51
+ return e.copyValue != null && e.copyValue !== "" && (t = /* @__PURE__ */ o(u, {
52
52
  value: e.copyValue,
53
53
  copyValue: e.copyValue,
54
54
  truncate: !1,
55
55
  copyLabel: y("common.actions.copy"),
56
56
  copiedLabel: y("common.actions.copied")
57
- })), /* @__PURE__ */ c("div", {
57
+ })), /* @__PURE__ */ s("div", {
58
58
  className: "txvbqbfpn txvbqbh4x txvbqbhd8 txvbqbv7x",
59
- children: [/* @__PURE__ */ s("span", {
59
+ children: [/* @__PURE__ */ o("span", {
60
60
  className: "txvbqb96 txvbqb6a txvbqbmw7 txvbqb1bgt",
61
61
  children: e.label
62
- }), /* @__PURE__ */ s("span", {
62
+ }), /* @__PURE__ */ o("span", {
63
63
  className: "txvbqb9j txvbqb1bgr txvbqbws9",
64
64
  children: t
65
65
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeEntitySummaryHeader.js","names":[],"sources":["../../../../../src/components/backoffice/detail/BackofficeEntitySummaryHeader.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { CopyableText } from '@plumile/ui/backoffice/atoms/copyable_text/CopyableText.js';\nimport { Tag } from '@plumile/ui/backoffice/atoms/tag/Tag.js';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport {\n BackofficeStatusMetaBadge,\n type BackofficeStatusMetaTone,\n} from './BackofficeStatusMetaBadge.js';\nimport * as styles from './backofficeEntitySummaryHeader.css.js';\n\nexport type BackofficeEntitySummaryHeaderTone = BackofficeStatusMetaTone;\n\nexport type BackofficeEntitySummaryHeaderMetaItem = {\n readonly id: string;\n readonly label: string;\n readonly value: ReactNode;\n readonly copyValue?: string;\n readonly tone?: BackofficeEntitySummaryHeaderTone;\n};\n\nexport type BackofficeEntitySummaryHeaderAction = {\n readonly id: string;\n readonly label: string;\n readonly icon?: ReactNode;\n readonly disabled?: boolean;\n readonly loading?: boolean;\n readonly tone?: 'neutral' | 'primary' | 'danger';\n readonly onPress: () => void;\n};\n\nexport type BackofficeEntitySummaryHeaderProps = {\n readonly title: ReactNode;\n readonly entityLabel: string;\n readonly subtitle?: ReactNode;\n readonly status?: {\n readonly label: string;\n readonly tone: BackofficeEntitySummaryHeaderTone;\n };\n readonly meta?: readonly BackofficeEntitySummaryHeaderMetaItem[];\n readonly primaryActions?: readonly BackofficeEntitySummaryHeaderAction[];\n readonly secondaryActions?: readonly BackofficeEntitySummaryHeaderAction[];\n};\n\nconst resolveActionVariant = (\n tone: BackofficeEntitySummaryHeaderAction['tone'],\n): 'primary' | 'secondary' | 'danger' => {\n if (tone === 'danger') {\n return 'danger';\n }\n if (tone === 'neutral') {\n return 'secondary';\n }\n return 'primary';\n};\n\nconst renderAction = (\n action: BackofficeEntitySummaryHeaderAction,\n): JSX.Element => {\n return (\n <Button\n key={action.id}\n type=\"button\"\n variant={resolveActionVariant(action.tone)}\n size=\"small\"\n leftIcon={action.icon}\n disabled={action.disabled}\n isLoading={action.loading}\n onClick={action.onPress}\n >\n {action.label}\n </Button>\n );\n};\n\nexport const BackofficeEntitySummaryHeader = ({\n title,\n entityLabel,\n subtitle,\n status,\n meta,\n primaryActions,\n secondaryActions,\n}: BackofficeEntitySummaryHeaderProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const actions = [...(primaryActions ?? []), ...(secondaryActions ?? [])];\n\n return (\n <header className={styles.root}>\n <div className={styles.top}>\n <div className={styles.identity}>\n <div className={styles.titleRow}>\n <h1 className={styles.title}>{title}</h1>\n <Tag tone=\"neutral\">{entityLabel}</Tag>\n {status != null && <BackofficeStatusMetaBadge status={status} />}\n </div>\n {subtitle != null && (\n <div className={styles.subtitle}>{subtitle}</div>\n )}\n </div>\n {actions.length > 0 && (\n <div className={styles.actions}>{actions.map(renderAction)}</div>\n )}\n </div>\n {meta != null && meta.length > 0 && (\n <div className={styles.meta}>\n {meta.map((item) => {\n let valueNode = item.value;\n if (item.copyValue != null && item.copyValue !== '') {\n valueNode = (\n <CopyableText\n value={item.copyValue}\n copyValue={item.copyValue}\n truncate={false}\n copyLabel={t('common.actions.copy')}\n copiedLabel={t('common.actions.copied')}\n />\n );\n }\n\n return (\n <div key={item.id} className={styles.metaItem}>\n <span className={styles.metaLabel}>{item.label}</span>\n <span className={styles.metaValue}>{valueNode}</span>\n </div>\n );\n })}\n </div>\n )}\n </header>\n );\n};\n\nexport default BackofficeEntitySummaryHeader;\n"],"mappings":";;;;;;;;AA6CA,IAAM,KACJ,MAEI,MAAS,WACJ,WAEL,MAAS,YACJ,cAEF,WAGH,KACJ,MAGE,kBAAC,GAAD;CAEE,MAAK;CACL,SAAS,EAAqB,EAAO,IAAI;CACzC,MAAK;CACL,UAAU,EAAO;CACjB,UAAU,EAAO;CACjB,WAAW,EAAO;CAClB,SAAS,EAAO;CAEf,UAAA,EAAO;AACF,GAVD,EAAO,EAUN,GAIC,KAAiC,EAC5C,OAAA,GACA,gBACA,UAAA,GACA,WACA,MAAA,GACA,mBACA,0BACqD;CACrD,IAAM,EAAE,SAAM,EAA8B,GACtC,IAAU,CAAC,GAAI,KAAkB,CAAC,GAAI,GAAI,KAAoB,CAAC,CAAE;CAEvE,OACE,kBAAC,UAAD;EAAQ,WAAW;EAAnB,UAAA,CACE,kBAAC,OAAD;GAAK,WAAW;GAAhB,UAAA,CACE,kBAAC,OAAD;IAAK,WAAW;IAAhB,UAAA,CACE,kBAAC,OAAD;KAAK,WAAW;KAAhB,UAAA;MACE,kBAAC,MAAD;OAAI,WAAW;OAAe,UAAA;MAAU,CAAA;MACxC,kBAAC,GAAD;OAAK,MAAK;OAAW,UAAA;MAAiB,CAAA;MACrC,KAAU,QAAQ,kBAAC,GAAD,EAAmC,UAAS,CAAA;KAC5D;IACJ,CAAA,GAAA,KAAY,QACX,kBAAC,OAAD;KAAK,WAAW;KAAkB,UAAA;IAAc,CAAA,CAE/C;GACJ,CAAA,GAAA,EAAQ,SAAS,KAChB,kBAAC,OAAD;IAAK,WAAW;IAAiB,UAAA,EAAQ,IAAI,CAAY;GAAO,CAAA,CAE/D;EACJ,CAAA,GAAA,KAAQ,QAAQ,EAAK,SAAS,KAC7B,kBAAC,OAAD;GAAK,WAAW;GACb,UAAA,EAAK,KAAK,MAAS;IAClB,IAAI,IAAY,EAAK;IAarB,OAZI,EAAK,aAAa,QAAQ,EAAK,cAAc,OAC/C,IACE,kBAAC,GAAD;KACE,OAAO,EAAK;KACZ,WAAW,EAAK;KAChB,UAAU;KACV,WAAW,EAAE,qBAAqB;KAClC,aAAa,EAAE,uBAAuB;IACvC,CAAA,IAKH,kBAAC,OAAD;KAAmB,WAAW;KAA9B,UAAA,CACE,kBAAC,QAAD;MAAM,WAAW;MAAmB,UAAA,EAAK;KAAY,CAAA,GACrD,kBAAC,QAAD;MAAM,WAAW;MAAmB,UAAA;KAAgB,CAAA,CACjD;IAHK,GAAA,EAAK,EAGV;GAET,CAAC;EACE,CAAA,CAED;;AAEZ"}
1
+ {"version":3,"file":"BackofficeEntitySummaryHeader.js","names":[],"sources":["../../../../../src/components/backoffice/detail/BackofficeEntitySummaryHeader.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { CopyableText } from '@plumile/ui/backoffice/atoms/copyable_text/CopyableText.js';\nimport { Tag } from '@plumile/ui/backoffice/atoms/tag/Tag.js';\nimport {\n BackofficeStatusMetaBadge,\n type BackofficeStatusMetaTone,\n} from '@plumile/ui/backoffice/molecules/backoffice_status_meta_badge/BackofficeStatusMetaBadge.js';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport * as styles from './backofficeEntitySummaryHeader.css.js';\n\nexport type BackofficeEntitySummaryHeaderTone = BackofficeStatusMetaTone;\n\nexport type BackofficeEntitySummaryHeaderMetaItem = {\n readonly id: string;\n readonly label: string;\n readonly value: ReactNode;\n readonly copyValue?: string;\n readonly tone?: BackofficeEntitySummaryHeaderTone;\n};\n\nexport type BackofficeEntitySummaryHeaderAction = {\n readonly id: string;\n readonly label: string;\n readonly icon?: ReactNode;\n readonly disabled?: boolean;\n readonly loading?: boolean;\n readonly tone?: 'neutral' | 'primary' | 'danger';\n readonly onPress: () => void;\n};\n\nexport type BackofficeEntitySummaryHeaderProps = {\n readonly title: ReactNode;\n readonly entityLabel: string;\n readonly subtitle?: ReactNode;\n readonly status?: {\n readonly label: string;\n readonly tone: BackofficeEntitySummaryHeaderTone;\n };\n readonly meta?: readonly BackofficeEntitySummaryHeaderMetaItem[];\n readonly primaryActions?: readonly BackofficeEntitySummaryHeaderAction[];\n readonly secondaryActions?: readonly BackofficeEntitySummaryHeaderAction[];\n};\n\nconst resolveActionVariant = (\n tone: BackofficeEntitySummaryHeaderAction['tone'],\n): 'primary' | 'secondary' | 'danger' => {\n if (tone === 'danger') {\n return 'danger';\n }\n if (tone === 'neutral') {\n return 'secondary';\n }\n return 'primary';\n};\n\nconst renderAction = (\n action: BackofficeEntitySummaryHeaderAction,\n): JSX.Element => {\n return (\n <Button\n key={action.id}\n type=\"button\"\n variant={resolveActionVariant(action.tone)}\n size=\"small\"\n leftIcon={action.icon}\n disabled={action.disabled}\n isLoading={action.loading}\n onClick={action.onPress}\n >\n {action.label}\n </Button>\n );\n};\n\nexport const BackofficeEntitySummaryHeader = ({\n title,\n entityLabel,\n subtitle,\n status,\n meta,\n primaryActions,\n secondaryActions,\n}: BackofficeEntitySummaryHeaderProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const actions = [...(primaryActions ?? []), ...(secondaryActions ?? [])];\n\n return (\n <header className={styles.root}>\n <div className={styles.top}>\n <div className={styles.identity}>\n <div className={styles.titleRow}>\n <h1 className={styles.title}>{title}</h1>\n <Tag tone=\"neutral\">{entityLabel}</Tag>\n {status != null && <BackofficeStatusMetaBadge status={status} />}\n </div>\n {subtitle != null && (\n <div className={styles.subtitle}>{subtitle}</div>\n )}\n </div>\n {actions.length > 0 && (\n <div className={styles.actions}>{actions.map(renderAction)}</div>\n )}\n </div>\n {meta != null && meta.length > 0 && (\n <div className={styles.meta}>\n {meta.map((item) => {\n let valueNode = item.value;\n if (item.copyValue != null && item.copyValue !== '') {\n valueNode = (\n <CopyableText\n value={item.copyValue}\n copyValue={item.copyValue}\n truncate={false}\n copyLabel={t('common.actions.copy')}\n copiedLabel={t('common.actions.copied')}\n />\n );\n }\n\n return (\n <div key={item.id} className={styles.metaItem}>\n <span className={styles.metaLabel}>{item.label}</span>\n <span className={styles.metaValue}>{valueNode}</span>\n </div>\n );\n })}\n </div>\n )}\n </header>\n );\n};\n\nexport default BackofficeEntitySummaryHeader;\n"],"mappings":";;;;;;;;AA6CA,IAAM,KACJ,MAEI,MAAS,WACJ,WAEL,MAAS,YACJ,cAEF,WAGH,KACJ,MAGE,kBAAC,GAAD;CAEE,MAAK;CACL,SAAS,EAAqB,EAAO,IAAI;CACzC,MAAK;CACL,UAAU,EAAO;CACjB,UAAU,EAAO;CACjB,WAAW,EAAO;CAClB,SAAS,EAAO;CAEf,UAAA,EAAO;AACF,GAVD,EAAO,EAUN,GAIC,KAAiC,EAC5C,OAAA,GACA,gBACA,UAAA,GACA,WACA,MAAA,GACA,mBACA,0BACqD;CACrD,IAAM,EAAE,SAAM,EAA8B,GACtC,IAAU,CAAC,GAAI,KAAkB,CAAC,GAAI,GAAI,KAAoB,CAAC,CAAE;CAEvE,OACE,kBAAC,UAAD;EAAQ,WAAW;EAAnB,UAAA,CACE,kBAAC,OAAD;GAAK,WAAW;GAAhB,UAAA,CACE,kBAAC,OAAD;IAAK,WAAW;IAAhB,UAAA,CACE,kBAAC,OAAD;KAAK,WAAW;KAAhB,UAAA;MACE,kBAAC,MAAD;OAAI,WAAW;OAAe,UAAA;MAAU,CAAA;MACxC,kBAAC,GAAD;OAAK,MAAK;OAAW,UAAA;MAAiB,CAAA;MACrC,KAAU,QAAQ,kBAAC,GAAD,EAAmC,UAAS,CAAA;KAC5D;IACJ,CAAA,GAAA,KAAY,QACX,kBAAC,OAAD;KAAK,WAAW;KAAkB,UAAA;IAAc,CAAA,CAE/C;GACJ,CAAA,GAAA,EAAQ,SAAS,KAChB,kBAAC,OAAD;IAAK,WAAW;IAAiB,UAAA,EAAQ,IAAI,CAAY;GAAO,CAAA,CAE/D;EACJ,CAAA,GAAA,KAAQ,QAAQ,EAAK,SAAS,KAC7B,kBAAC,OAAD;GAAK,WAAW;GACb,UAAA,EAAK,KAAK,MAAS;IAClB,IAAI,IAAY,EAAK;IAarB,OAZI,EAAK,aAAa,QAAQ,EAAK,cAAc,OAC/C,IACE,kBAAC,GAAD;KACE,OAAO,EAAK;KACZ,WAAW,EAAK;KAChB,UAAU;KACV,WAAW,EAAE,qBAAqB;KAClC,aAAa,EAAE,uBAAuB;IACvC,CAAA,IAKH,kBAAC,OAAD;KAAmB,WAAW;KAA9B,UAAA,CACE,kBAAC,QAAD;MAAM,WAAW;MAAmB,UAAA,EAAK;KAAY,CAAA,GACrD,kBAAC,QAAD;MAAM,WAAW;MAAmB,UAAA;KAAgB,CAAA,CACjD;IAHK,GAAA,EAAK,EAGV;GAET,CAAC;EACE,CAAA,CAED;;AAEZ"}