@plumile/backoffice-react 0.1.188 → 0.1.190

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 (127) hide show
  1. package/lib/esm/auth/login/LoginFlow.js.map +1 -1
  2. package/lib/esm/auth/login/MethodChooser.js.map +1 -1
  3. package/lib/esm/auth/login/MfaChallengeForm.js.map +1 -1
  4. package/lib/esm/auth/login/PasskeyLoginForm.js.map +1 -1
  5. package/lib/esm/auth/login/loginPage.css.js +2 -0
  6. package/lib/esm/auth/login/synchronizeAuthStatusQuery.js.map +1 -1
  7. package/lib/esm/auth/pages/AcceptInvitationScreen.js.map +1 -1
  8. package/lib/esm/auth/pages/PasswordResetCompleteScreen.js.map +1 -1
  9. package/lib/esm/auth/pages/PasswordResetRequestScreen.js.map +1 -1
  10. package/lib/esm/auth/pages/VerifyEmailScreen.js.map +1 -1
  11. package/lib/esm/components/backoffice/actions/LazyBackofficeEntityActionFormDialog.js.map +1 -1
  12. package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js.map +1 -1
  13. package/lib/esm/components/backoffice/columns/buildDataTableColumns.js.map +1 -1
  14. package/lib/esm/components/backoffice/detail/BackofficeLifecycleTimelineSection.js.map +1 -1
  15. package/lib/esm/components/backoffice/detail/BackofficeTokenUsageBreakdown.js.map +1 -1
  16. package/lib/esm/components/backoffice/detail/backofficeDetailRelationLink.css.js +1 -0
  17. package/lib/esm/components/backoffice/detail/backofficeEntitySummaryHeader.css.js +0 -1
  18. package/lib/esm/components/backoffice/detail/createBackofficeEntityLinkProps.js.map +1 -1
  19. package/lib/esm/components/backoffice/detail/detailPayloadUtils.js.map +1 -1
  20. package/lib/esm/components/backoffice/filters/backofficeFilterAction.css.js +0 -1
  21. package/lib/esm/components/backoffice/filters/deferredFilterSearchInput.css.js +0 -1
  22. package/lib/esm/components/backoffice/layout/breadcrumb/assertValidBreadcrumb.js.map +1 -1
  23. package/lib/esm/components/backoffice/layout/buildSidebarSections.js.map +1 -1
  24. package/lib/esm/components/backoffice/layout/mapViewerToSidebarProfileView.js.map +1 -1
  25. package/lib/esm/components/backoffice/layout/sidebarUtils.js.map +1 -1
  26. package/lib/esm/components/backoffice/links/resolveBackofficeLink.js.map +1 -1
  27. package/lib/esm/components/backoffice/links/resolveBackofficeTargetIcon.js.map +1 -1
  28. package/lib/esm/components/backoffice/list/RowFlagsCell.js.map +1 -1
  29. package/lib/esm/components/backoffice/pickers/EntityIdPickerDialog.js.map +1 -1
  30. package/lib/esm/components/backoffice/refs/BackofficeLazyEntityCount.js.map +1 -1
  31. package/lib/esm/components/backoffice/refs/BackofficeRelatedCountLink.js.map +1 -1
  32. package/lib/esm/components/backoffice/routing/BackofficeContentBoundary.js.map +1 -1
  33. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js +368 -281
  34. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
  35. package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js +2 -2
  36. package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js.map +1 -1
  37. package/lib/esm/components/backoffice/shared/backofficeFilterableCell.css.js +1 -1
  38. package/lib/esm/components/backoffice/technical/TechnicalIdentifierValue.js.map +1 -1
  39. package/lib/esm/filters/filterHelpers.js +1 -1
  40. package/lib/esm/filters/filterHelpers.js.map +1 -1
  41. package/lib/esm/hooks/useAuth.js.map +1 -1
  42. package/lib/esm/hooks/useBackofficeAuth.js.map +1 -1
  43. package/lib/esm/hooks/useBackofficeInfiniteScrollSentinel.js.map +1 -1
  44. package/lib/esm/hooks/useBackofficeListUrlState.js.map +1 -1
  45. package/lib/esm/hooks/useBackofficeSessionAuth.js.map +1 -1
  46. package/lib/esm/hooks/useConditionalSubscription.js.map +1 -1
  47. package/lib/esm/hooks/useSidebarGroupCollapse.js.map +1 -1
  48. package/lib/esm/i18n/createI18nInstance.js.map +1 -1
  49. package/lib/esm/i18n/locales/en/backofficeReact.js +409 -405
  50. package/lib/esm/i18n/locales/en/backofficeReact.js.map +1 -1
  51. package/lib/esm/i18n/locales/fr/backofficeReact.js +412 -407
  52. package/lib/esm/i18n/locales/fr/backofficeReact.js.map +1 -1
  53. package/lib/esm/i18n/mergeResourceLanguages.js.map +1 -1
  54. package/lib/esm/i18n/resources.js +1 -1
  55. package/lib/esm/i18n/resources.js.map +1 -1
  56. package/lib/esm/i18n/useBackofficeFormats.js.map +1 -1
  57. package/lib/esm/modules/base64.js.map +1 -1
  58. package/lib/esm/modules/formatFileSize.js.map +1 -1
  59. package/lib/esm/modules/uploads.js +17 -17
  60. package/lib/esm/modules/uploads.js.map +1 -1
  61. package/lib/esm/modules/webauthn.js.map +1 -1
  62. package/lib/esm/node_modules/@babel/runtime/helpers/objectSpread2.js.map +1 -1
  63. package/lib/esm/node_modules/@babel/runtime/helpers/toPrimitive.js.map +1 -1
  64. package/lib/esm/node_modules/@babel/runtime/helpers/toPropertyKey.js.map +1 -1
  65. package/lib/esm/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js.map +1 -1
  66. package/lib/esm/node_modules/@vanilla-extract/recipes/dist/createRuntimeFn-62c9670f.esm.js +1 -1
  67. package/lib/esm/node_modules/@vanilla-extract/recipes/dist/createRuntimeFn-62c9670f.esm.js.map +1 -1
  68. package/lib/esm/node_modules/fbjs/lib/areEqual.js.map +1 -1
  69. package/lib/esm/node_modules/relay-test-utils/lib/RelayMockPayloadGenerator.js.map +1 -1
  70. package/lib/esm/node_modules/relay-test-utils/lib/RelayModernMockEnvironment.js.map +1 -1
  71. package/lib/esm/node_modules/relay-test-utils/lib/RelayResolverTestUtils.js.map +1 -1
  72. package/lib/esm/pages/BackofficeDashboardPage.js.map +1 -1
  73. package/lib/esm/pages/BackofficeDashboardWidgetContent.js.map +1 -1
  74. package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js.map +1 -1
  75. package/lib/esm/pages/BackofficeEntityDetailPage.js.map +1 -1
  76. package/lib/esm/pages/BackofficeEntityDetailPage.view-helpers.js.map +1 -1
  77. package/lib/esm/pages/BackofficeEntityListDataPage.js +77 -70
  78. package/lib/esm/pages/BackofficeEntityListDataPage.js.map +1 -1
  79. package/lib/esm/pages/BackofficeEntityListPage.helpers.js +5 -5
  80. package/lib/esm/pages/BackofficeEntityListPage.helpers.js.map +1 -1
  81. package/lib/esm/pages/BackofficeEntityListPage.js +89 -85
  82. package/lib/esm/pages/BackofficeEntityListPage.js.map +1 -1
  83. package/lib/esm/pages/BackofficeEntityListRouteContext.js.map +1 -1
  84. package/lib/esm/pages/BackofficeHubPage.js.map +1 -1
  85. package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
  86. package/lib/esm/pages/BackofficeLoginPage.js.map +1 -1
  87. package/lib/esm/pages/BackofficePasswordResetRequestPage.js.map +1 -1
  88. package/lib/esm/pages/BackofficeVerifyEmailPage.js.map +1 -1
  89. package/lib/esm/pages/detail/BackofficeEntityDetailManifestFallback.js.map +1 -1
  90. package/lib/esm/pages/detail/pageResolution.js.map +1 -1
  91. package/lib/esm/provider/BackofficeListUiStateContext.js +88 -0
  92. package/lib/esm/provider/BackofficeListUiStateContext.js.map +1 -0
  93. package/lib/esm/provider/BackofficeProvider.js +80 -79
  94. package/lib/esm/provider/BackofficeProvider.js.map +1 -1
  95. package/lib/esm/provider/entityRegistry.js.map +1 -1
  96. package/lib/esm/provider/lazyValue.js.map +1 -1
  97. package/lib/esm/provider/useBackofficeEntityLoader.js.map +1 -1
  98. package/lib/esm/relay/connectionUtils.js.map +1 -1
  99. package/lib/esm/relay/envHelpers.js.map +1 -1
  100. package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
  101. package/lib/esm/storybook/relay/RelayStory.js.map +1 -1
  102. package/lib/esm/storybook/relay/mockResolvers.js.map +1 -1
  103. package/lib/types/components/backoffice/detail/BackofficeLifecycleTimelineSection.d.ts.map +1 -1
  104. package/lib/types/components/backoffice/pickers/EntityIdPickerDialog.d.ts.map +1 -1
  105. package/lib/types/components/backoffice/scaffolds/BackofficeEntityListScaffold.d.ts +2 -0
  106. package/lib/types/components/backoffice/scaffolds/BackofficeEntityListScaffold.d.ts.map +1 -1
  107. package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts +2 -0
  108. package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts.map +1 -1
  109. package/lib/types/components/backoffice/technical/TechnicalIdentifierValue.d.ts.map +1 -1
  110. package/lib/types/filters/filterHelpers.d.ts.map +1 -1
  111. package/lib/types/hooks/useAuth.d.ts.map +1 -1
  112. package/lib/types/i18n/resources.d.ts +7 -0
  113. package/lib/types/i18n/resources.d.ts.map +1 -1
  114. package/lib/types/modules/uploads.d.ts.map +1 -1
  115. package/lib/types/modules/webauthn.d.ts.map +1 -1
  116. package/lib/types/pages/BackofficeEntityListDataPage.d.ts.map +1 -1
  117. package/lib/types/pages/BackofficeEntityListPage.d.ts.map +1 -1
  118. package/lib/types/pages/BackofficeEntityListRouteContext.d.ts +2 -0
  119. package/lib/types/pages/BackofficeEntityListRouteContext.d.ts.map +1 -1
  120. package/lib/types/pages/BackofficePasswordResetRequestPage.d.ts.map +1 -1
  121. package/lib/types/pages/BackofficeVerifyEmailPage.d.ts.map +1 -1
  122. package/lib/types/pages/detail/pageResolution.d.ts.map +1 -1
  123. package/lib/types/provider/BackofficeListUiStateContext.d.ts +21 -0
  124. package/lib/types/provider/BackofficeListUiStateContext.d.ts.map +1 -0
  125. package/lib/types/provider/BackofficeProvider.d.ts.map +1 -1
  126. package/lib/types/provider/types.d.ts.map +1 -1
  127. package/package.json +16 -16
@@ -1 +1 @@
1
- {"version":3,"file":"useBackofficeAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeAuth.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLTaggedNode, PayloadError } from 'relay-runtime';\n\nimport {\n createUseAuth,\n type UseAuthReturn,\n type AcceptInvitationResponse,\n type AcceptInvitationVariables,\n type BeginAuthenticationResponse,\n type BeginAuthenticationVariables,\n type BeginPasskeyLoginResponse,\n type BeginPasskeyLoginVariables,\n type CompleteMfaResponse,\n type CompleteMfaVariables,\n type FinishPasskeyLoginResponse,\n type FinishPasskeyLoginVariables,\n type LoginResponse,\n type LoginVariables,\n type LogoutResponse,\n type LogoutVariables,\n} from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport type { BackofficeLazyValue } from '../provider/lazyValue.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\n\nconst { commitMutation } = ReactRelay;\n\ntype MutationCommitConfig<TVariables, TResponse> = {\n variables: TVariables;\n onCompleted?: (\n response: TResponse,\n errors: readonly PayloadError[] | null,\n ) => void;\n onError?: (error: Error) => void;\n};\n\nconst toMutationLoadError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Unable to load auth mutation.');\n};\n\nconst useDeferredMutation = <TVariables extends object, TResponse>(\n loadMutation: () => Promise<GraphQLTaggedNode | null>,\n) => {\n const relayEnvironment = useRelayEnvironment();\n const [inFlightCount, setInFlightCount] = useState(0);\n\n const commit = useCallback(\n (config: MutationCommitConfig<TVariables, TResponse>) => {\n setInFlightCount((count) => {\n return count + 1;\n });\n\n const finish = () => {\n setInFlightCount((count) => {\n return Math.max(0, count - 1);\n });\n };\n\n loadMutation()\n .then((mutation) => {\n if (mutation == null) {\n throw new Error('Missing auth mutation config.');\n }\n\n commitMutation(relayEnvironment, {\n mutation,\n variables: config.variables as Record<string, unknown>,\n onCompleted: (response, errors) => {\n finish();\n config.onCompleted?.(response as TResponse, errors ?? null);\n },\n onError: (error) => {\n finish();\n config.onError?.(error);\n },\n });\n })\n .catch((error: unknown) => {\n finish();\n config.onError?.(toMutationLoadError(error));\n });\n },\n [loadMutation, relayEnvironment],\n );\n\n return {\n commit,\n isInFlight: inFlightCount > 0,\n };\n};\n\nconst loadOptionalMutation = async <TConfig>(\n eagerMutation: GraphQLTaggedNode | null | undefined,\n lazyConfig: BackofficeLazyValue<TConfig> | null | undefined,\n selectMutation: (config: TConfig) => GraphQLTaggedNode,\n): Promise<GraphQLTaggedNode | null> => {\n if (eagerMutation != null) {\n return eagerMutation;\n }\n if (lazyConfig == null) {\n return null;\n }\n const loadedConfig = await lazyConfig.load();\n return selectMutation(loadedConfig);\n};\n\n/**\n * Provides auth actions/state backed by Relay mutations from BackofficeProvider.\n */\nexport function useBackofficeAuth(): UseAuthReturn {\n const { auth: authConfig } = useBackofficeConfig();\n const { commit: commitLogin, isInFlight: isLoginInFlight } =\n useDeferredMutation<LoginVariables, LoginResponse>(\n useCallback(async () => {\n const loginConfig = authConfig.login.get();\n return loadOptionalMutation(\n loginConfig?.loginMutation,\n authConfig.login,\n (config) => {\n return config.loginMutation;\n },\n );\n }, [authConfig.login]),\n );\n const { commit: commitLogout, isInFlight: isLogoutInFlight } =\n useDeferredMutation<LogoutVariables, LogoutResponse>(\n useCallback(async () => {\n const logoutConfig = await authConfig.logout.load();\n return logoutConfig.logoutMutation;\n }, [authConfig.logout]),\n );\n const { commit: commitCompleteMfa, isInFlight: isCompleteMfaInFlight } =\n useDeferredMutation<CompleteMfaVariables, CompleteMfaResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.completeMfaMutation,\n authConfig.completeMfa,\n (config) => {\n return config.completeMfaMutation;\n },\n );\n }, [authConfig.completeMfa, authConfig.login]),\n );\n const {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n } = useDeferredMutation<\n BeginPasskeyLoginVariables,\n BeginPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.beginPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n } = useDeferredMutation<\n FinishPasskeyLoginVariables,\n FinishPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.finishPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.finishPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n } = useDeferredMutation<\n BeginAuthenticationVariables,\n BeginAuthenticationResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginAuthenticationMutation,\n authConfig.authentication,\n (config) => {\n return config.beginAuthenticationMutation;\n },\n );\n }, [authConfig.authentication, authConfig.login]),\n );\n const {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n } = useDeferredMutation<AcceptInvitationVariables, AcceptInvitationResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.acceptInvitationMutation,\n authConfig.acceptInvitation,\n (config) => {\n return config.acceptInvitationMutation;\n },\n );\n }, [authConfig.acceptInvitation, authConfig.login]),\n );\n const hasAcceptInvitationMutation =\n authConfig.login.get()?.acceptInvitationMutation != null ||\n authConfig.acceptInvitation != null;\n\n const useAuthWithMutations = useMemo(() => {\n let acceptInvitation:\n | {\n commit: typeof commitAcceptInvitation;\n isInFlight: boolean;\n }\n | undefined;\n if (hasAcceptInvitationMutation) {\n acceptInvitation = {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n };\n }\n return createUseAuth({\n login: { commit: commitLogin, isInFlight: isLoginInFlight },\n logout: { commit: commitLogout, isInFlight: isLogoutInFlight },\n completeMfa: {\n commit: commitCompleteMfa,\n isInFlight: isCompleteMfaInFlight,\n },\n beginPasskeyLogin: {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n },\n finishPasskeyLogin: {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n },\n beginAuthentication: {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n },\n acceptInvitation,\n });\n }, [\n commitAcceptInvitation,\n commitBeginAuthentication,\n commitBeginPasskeyLogin,\n commitCompleteMfa,\n commitFinishPasskeyLogin,\n commitLogin,\n commitLogout,\n hasAcceptInvitationMutation,\n isAcceptInvitationInFlight,\n isBeginAuthenticationInFlight,\n isBeginPasskeyLoginInFlight,\n isCompleteMfaInFlight,\n isFinishPasskeyLoginInFlight,\n isLoginInFlight,\n isLogoutInFlight,\n ]);\n\n return useAuthWithMutations();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useBackofficeAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeAuth.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLTaggedNode, PayloadError } from 'relay-runtime';\n\nimport {\n createUseAuth,\n type UseAuthReturn,\n type AcceptInvitationResponse,\n type AcceptInvitationVariables,\n type BeginAuthenticationResponse,\n type BeginAuthenticationVariables,\n type BeginPasskeyLoginResponse,\n type BeginPasskeyLoginVariables,\n type CompleteMfaResponse,\n type CompleteMfaVariables,\n type FinishPasskeyLoginResponse,\n type FinishPasskeyLoginVariables,\n type LoginResponse,\n type LoginVariables,\n type LogoutResponse,\n type LogoutVariables,\n} from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport type { BackofficeLazyValue } from '../provider/lazyValue.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\n\nconst { commitMutation } = ReactRelay;\n\ntype MutationCommitConfig<TVariables, TResponse> = {\n variables: TVariables;\n onCompleted?: (\n response: TResponse,\n errors: readonly PayloadError[] | null,\n ) => void;\n onError?: (error: Error) => void;\n};\n\nconst toMutationLoadError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Unable to load auth mutation.');\n};\n\nconst useDeferredMutation = <TVariables extends object, TResponse>(\n loadMutation: () => Promise<GraphQLTaggedNode | null>,\n) => {\n const relayEnvironment = useRelayEnvironment();\n const [inFlightCount, setInFlightCount] = useState(0);\n\n const commit = useCallback(\n (config: MutationCommitConfig<TVariables, TResponse>) => {\n setInFlightCount((count) => {\n return count + 1;\n });\n\n const finish = () => {\n setInFlightCount((count) => {\n return Math.max(0, count - 1);\n });\n };\n\n loadMutation()\n .then((mutation) => {\n if (mutation == null) {\n throw new Error('Missing auth mutation config.');\n }\n\n commitMutation(relayEnvironment, {\n mutation,\n variables: config.variables as Record<string, unknown>,\n onCompleted: (response, errors) => {\n finish();\n config.onCompleted?.(response as TResponse, errors ?? null);\n },\n onError: (error) => {\n finish();\n config.onError?.(error);\n },\n });\n })\n .catch((error: unknown) => {\n finish();\n config.onError?.(toMutationLoadError(error));\n });\n },\n [loadMutation, relayEnvironment],\n );\n\n return {\n commit,\n isInFlight: inFlightCount > 0,\n };\n};\n\nconst loadOptionalMutation = async <TConfig>(\n eagerMutation: GraphQLTaggedNode | null | undefined,\n lazyConfig: BackofficeLazyValue<TConfig> | null | undefined,\n selectMutation: (config: TConfig) => GraphQLTaggedNode,\n): Promise<GraphQLTaggedNode | null> => {\n if (eagerMutation != null) {\n return eagerMutation;\n }\n if (lazyConfig == null) {\n return null;\n }\n const loadedConfig = await lazyConfig.load();\n return selectMutation(loadedConfig);\n};\n\n/**\n * Provides auth actions/state backed by Relay mutations from BackofficeProvider.\n */\nexport function useBackofficeAuth(): UseAuthReturn {\n const { auth: authConfig } = useBackofficeConfig();\n const { commit: commitLogin, isInFlight: isLoginInFlight } =\n useDeferredMutation<LoginVariables, LoginResponse>(\n useCallback(async () => {\n const loginConfig = authConfig.login.get();\n return loadOptionalMutation(\n loginConfig?.loginMutation,\n authConfig.login,\n (config) => {\n return config.loginMutation;\n },\n );\n }, [authConfig.login]),\n );\n const { commit: commitLogout, isInFlight: isLogoutInFlight } =\n useDeferredMutation<LogoutVariables, LogoutResponse>(\n useCallback(async () => {\n const logoutConfig = await authConfig.logout.load();\n return logoutConfig.logoutMutation;\n }, [authConfig.logout]),\n );\n const { commit: commitCompleteMfa, isInFlight: isCompleteMfaInFlight } =\n useDeferredMutation<CompleteMfaVariables, CompleteMfaResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.completeMfaMutation,\n authConfig.completeMfa,\n (config) => {\n return config.completeMfaMutation;\n },\n );\n }, [authConfig.completeMfa, authConfig.login]),\n );\n const {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n } = useDeferredMutation<\n BeginPasskeyLoginVariables,\n BeginPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.beginPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n } = useDeferredMutation<\n FinishPasskeyLoginVariables,\n FinishPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.finishPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.finishPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n } = useDeferredMutation<\n BeginAuthenticationVariables,\n BeginAuthenticationResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginAuthenticationMutation,\n authConfig.authentication,\n (config) => {\n return config.beginAuthenticationMutation;\n },\n );\n }, [authConfig.authentication, authConfig.login]),\n );\n const {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n } = useDeferredMutation<AcceptInvitationVariables, AcceptInvitationResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.acceptInvitationMutation,\n authConfig.acceptInvitation,\n (config) => {\n return config.acceptInvitationMutation;\n },\n );\n }, [authConfig.acceptInvitation, authConfig.login]),\n );\n const hasAcceptInvitationMutation =\n authConfig.login.get()?.acceptInvitationMutation != null ||\n authConfig.acceptInvitation != null;\n\n const useAuthWithMutations = useMemo(() => {\n let acceptInvitation:\n | {\n commit: typeof commitAcceptInvitation;\n isInFlight: boolean;\n }\n | undefined;\n if (hasAcceptInvitationMutation) {\n acceptInvitation = {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n };\n }\n return createUseAuth({\n login: { commit: commitLogin, isInFlight: isLoginInFlight },\n logout: { commit: commitLogout, isInFlight: isLogoutInFlight },\n completeMfa: {\n commit: commitCompleteMfa,\n isInFlight: isCompleteMfaInFlight,\n },\n beginPasskeyLogin: {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n },\n finishPasskeyLogin: {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n },\n beginAuthentication: {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n },\n acceptInvitation,\n });\n }, [\n commitAcceptInvitation,\n commitBeginAuthentication,\n commitBeginPasskeyLogin,\n commitCompleteMfa,\n commitFinishPasskeyLogin,\n commitLogin,\n commitLogout,\n hasAcceptInvitationMutation,\n isAcceptInvitationInFlight,\n isBeginAuthenticationInFlight,\n isBeginPasskeyLoginInFlight,\n isCompleteMfaInFlight,\n isFinishPasskeyLoginInFlight,\n isLoginInFlight,\n isLogoutInFlight,\n ]);\n\n return useAuthWithMutations();\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBackofficeInfiniteScrollSentinel.js","names":[],"sources":["../../../src/hooks/useBackofficeInfiniteScrollSentinel.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type UseBackofficeInfiniteScrollSentinelOptions = {\n enabled: boolean;\n hasNextPage: boolean;\n isLoading: boolean;\n root?: Element | null;\n rootMargin?: string;\n threshold?: number;\n onIntersect: () => void;\n};\n\nexport type UseBackofficeInfiniteScrollSentinelResult = {\n sentinelRef: (node: HTMLElement | null) => void;\n};\n\n/**\n * Observes a sentinel element and triggers pagination when it enters the viewport.\n */\nexport function useBackofficeInfiniteScrollSentinel({\n enabled,\n hasNextPage,\n isLoading,\n onIntersect,\n root = null,\n rootMargin = '360px 0px',\n threshold = 0,\n}: UseBackofficeInfiniteScrollSentinelOptions): UseBackofficeInfiniteScrollSentinelResult {\n const [node, setNode] = useState<HTMLElement | null>(null);\n const onIntersectRef = useRef(onIntersect);\n const lastIntersectAtRef = useRef(0);\n\n useEffect(() => {\n onIntersectRef.current = onIntersect;\n }, [onIntersect]);\n\n useEffect(() => {\n if (!enabled || !hasNextPage || isLoading || node == null) {\n return () => {};\n }\n\n const triggerIntersect = () => {\n const now = Date.now();\n if (now - lastIntersectAtRef.current < 250) {\n return;\n }\n lastIntersectAtRef.current = now;\n onIntersectRef.current();\n };\n\n if (typeof IntersectionObserver === 'undefined') {\n triggerIntersect();\n return () => {};\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting === true) {\n triggerIntersect();\n }\n },\n {\n root,\n rootMargin,\n threshold,\n },\n );\n\n observer.observe(node);\n\n return () => {\n observer.disconnect();\n };\n }, [enabled, hasNextPage, isLoading, node, root, rootMargin, threshold]);\n\n const sentinelRef = useCallback((next: HTMLElement | null) => {\n setNode(next);\n }, []);\n\n return { sentinelRef };\n}\n"],"mappings":";;AAmBA,SAAgB,EAAoC,EAClD,YACA,gBACA,cACA,gBACA,UAAO,MACP,gBAAa,aACb,eAAY,KAC4E;CACxF,IAAM,CAAC,GAAM,KAAW,EAA6B,IAAI,GACnD,IAAiB,EAAO,CAAW,GACnC,IAAqB,EAAO,CAAC;CAkDnC,OAhDA,QAAgB;EACd,EAAe,UAAU;CAC3B,GAAG,CAAC,CAAW,CAAC,GAEhB,QAAgB;EACd,IAAI,CAAC,KAAW,CAAC,KAAe,KAAa,KAAQ,MACnD,aAAa,CAAC;EAGhB,IAAM,UAAyB;GAC7B,IAAM,IAAM,KAAK,IAAI;GACjB,IAAM,EAAmB,UAAU,QAGvC,EAAmB,UAAU,GAC7B,EAAe,QAAQ;EACzB;EAEA,IAAI,OAAO,uBAAyB,KAElC,OADA,EAAiB,SACJ,CAAC;EAGhB,IAAM,IAAW,IAAI,sBAClB,MAAY;GAEX,AADc,EAAQ,IACX,mBAAmB,MAC5B,EAAiB;EAErB,GACA;GACE;GACA;GACA;EACF,CACF;EAIA,OAFA,EAAS,QAAQ,CAAI,SAER;GACX,EAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAS;EAAa;EAAW;EAAM;EAAM;EAAY;CAAS,CAAC,GAMhE,EAAE,aAJW,GAAa,MAA6B;EAC5D,EAAQ,CAAI;CACd,GAAG,CAAC,CAEK,EAAY;AACvB"}
1
+ {"version":3,"file":"useBackofficeInfiniteScrollSentinel.js","names":[],"sources":["../../../src/hooks/useBackofficeInfiniteScrollSentinel.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type UseBackofficeInfiniteScrollSentinelOptions = {\n enabled: boolean;\n hasNextPage: boolean;\n isLoading: boolean;\n root?: Element | null;\n rootMargin?: string;\n threshold?: number;\n onIntersect: () => void;\n};\n\nexport type UseBackofficeInfiniteScrollSentinelResult = {\n sentinelRef: (node: HTMLElement | null) => void;\n};\n\n/**\n * Observes a sentinel element and triggers pagination when it enters the viewport.\n */\nexport function useBackofficeInfiniteScrollSentinel({\n enabled,\n hasNextPage,\n isLoading,\n onIntersect,\n root = null,\n rootMargin = '360px 0px',\n threshold = 0,\n}: UseBackofficeInfiniteScrollSentinelOptions): UseBackofficeInfiniteScrollSentinelResult {\n const [node, setNode] = useState<HTMLElement | null>(null);\n const onIntersectRef = useRef(onIntersect);\n const lastIntersectAtRef = useRef(0);\n\n useEffect(() => {\n onIntersectRef.current = onIntersect;\n }, [onIntersect]);\n\n useEffect(() => {\n if (!enabled || !hasNextPage || isLoading || node == null) {\n return () => {};\n }\n\n const triggerIntersect = () => {\n const now = Date.now();\n if (now - lastIntersectAtRef.current < 250) {\n return;\n }\n lastIntersectAtRef.current = now;\n onIntersectRef.current();\n };\n\n if (typeof IntersectionObserver === 'undefined') {\n triggerIntersect();\n return () => {};\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting === true) {\n triggerIntersect();\n }\n },\n {\n root,\n rootMargin,\n threshold,\n },\n );\n\n observer.observe(node);\n\n return () => {\n observer.disconnect();\n };\n }, [enabled, hasNextPage, isLoading, node, root, rootMargin, threshold]);\n\n const sentinelRef = useCallback((next: HTMLElement | null) => {\n setNode(next);\n }, []);\n\n return { sentinelRef };\n}\n"],"mappings":";;AAmBA,SAAgB,EAAoC,EAClD,YACA,gBACA,cACA,gBACA,UAAO,MACP,gBAAa,aACb,eAAY,KAC4E;CACxF,IAAM,CAAC,GAAM,KAAW,EAA6B,IAAI,GACnD,IAAiB,EAAO,CAAW,GACnC,IAAqB,EAAO,CAAC;CAkDnC,OAhDA,QAAgB;EACd,EAAe,UAAU;CAC3B,GAAG,CAAC,CAAW,CAAC,GAEhB,QAAgB;EACd,IAAI,CAAC,KAAW,CAAC,KAAe,KAAa,KAAQ,MACnD,aAAa,CAAC;EAGhB,IAAM,UAAyB;GAC7B,IAAM,IAAM,KAAK,IAAI;GACjB,IAAM,EAAmB,UAAU,QAGvC,EAAmB,UAAU,GAC7B,EAAe,QAAQ;EACzB;EAEA,IAAI,OAAO,uBAAyB,KAElC,OADA,EAAiB,SACJ,CAAC;EAGhB,IAAM,IAAW,IAAI,sBAClB,MAAY;GAEX,AADc,EAAQ,EAClB,EAAO,mBAAmB,MAC5B,EAAiB;EAErB,GACA;GACE;GACA;GACA;EACF,CACF;EAIA,OAFA,EAAS,QAAQ,CAAI,SAER;GACX,EAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAS;EAAa;EAAW;EAAM;EAAM;EAAY;CAAS,CAAC,GAMhE,EAAE,aAJW,GAAa,MAA6B;EAC5D,EAAQ,CAAI;CACd,GAAG,CAAC,CAEK,EAAY;AACvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBackofficeListUrlState.js","names":[],"sources":["../../../src/hooks/useBackofficeListUrlState.ts"],"sourcesContent":["import { startTransition, useCallback, useContext, useMemo } from 'react';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport type {\n BackofficeListState,\n BackofficeRuntimeResolvedListFacetConfig,\n} from '@plumile/backoffice-core/types.js';\n\n/** Normalizes a router `location.search` string into URLSearchParams. */\nfunction normalizeSearch(value: string): URLSearchParams {\n if (value.trim() === '') {\n return new URLSearchParams();\n }\n return new URLSearchParams(value);\n}\n\ntype ReturnValue<Where extends Record<string, unknown>, Sort extends string> = {\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n};\n\n/** Keeps list state in sync with the URL search params for backoffice pages. */\nexport function useBackofficeListUrlState<\n Where extends Record<string, unknown>,\n Sort extends string,\n>(config: BackofficeRuntimeResolvedListFacetConfig): ReturnValue<Where, Sort> {\n const routing = useContext(RoutingContext);\n const { hash, pathname, search } = useLocation();\n const fallbackState = useMemo(() => {\n return {\n where: null,\n sort: null,\n };\n }, []);\n\n const state = useMemo(() => {\n if (config.listUrlCodec == null) {\n return fallbackState;\n }\n return config.listUrlCodec.parse(\n normalizeSearch(search),\n ) as BackofficeListState<Where, Sort>;\n }, [config.listUrlCodec, fallbackState, search]);\n\n const pushState = useCallback(\n (next: BackofficeListState<Where, Sort>) => {\n if (routing == null) {\n return;\n }\n if (config.listUrlCodec == null) {\n return;\n }\n\n const codec = config.listUrlCodec as unknown as {\n serialize: (state: BackofficeListState<Where, Sort>) => URLSearchParams;\n };\n const params = codec.serialize(next);\n const qs = params.toString();\n\n let nextSearch = '';\n if (qs !== '') {\n nextSearch = `?${qs}`;\n }\n\n startTransition(() => {\n routing.history.push({\n pathname,\n search: nextSearch,\n hash,\n });\n });\n },\n [config.listUrlCodec, hash, pathname, routing],\n );\n\n return { state, pushState };\n}\n"],"mappings":";;;;AAUA,SAAS,EAAgB,GAAgC;CAIvD,OAHI,EAAM,KAAK,MAAM,KACZ,IAAI,gBAAgB,IAEtB,IAAI,gBAAgB,CAAK;AAClC;AAQA,SAAgB,EAGd,GAA4E;CAC5E,IAAM,IAAU,EAAW,CAAc,GACnC,EAAE,SAAM,aAAU,cAAW,EAAY,GACzC,IAAgB,SACb;EACL,OAAO;EACP,MAAM;CACR,IACC,CAAC,CAAC;CA0CL,OAAO;EAAE,OAxCK,QACR,EAAO,gBAAgB,OAClB,IAEF,EAAO,aAAa,MACzB,EAAgB,CAAM,CACxB,GACC;GAAC,EAAO;GAAc;GAAe;EAAM,CAiCrC;EAAO,WA/BE,GACf,MAA2C;GAI1C,IAHI,KAAW,QAGX,EAAO,gBAAgB,MACzB;GAOF,IAAM,IAJQ,EAAO,aAGA,UAAU,CACpB,EAAO,SAAS,GAEvB,IAAa;GAKjB,AAJI,MAAO,OACT,IAAa,IAAI,MAGnB,QAAsB;IACpB,EAAQ,QAAQ,KAAK;KACnB;KACA,QAAQ;KACR;IACF,CAAC;GACH,CAAC;EACH,GACA;GAAC,EAAO;GAAc;GAAM;GAAU;EAAO,CAG/B;CAAU;AAC5B"}
1
+ {"version":3,"file":"useBackofficeListUrlState.js","names":[],"sources":["../../../src/hooks/useBackofficeListUrlState.ts"],"sourcesContent":["import { startTransition, useCallback, useContext, useMemo } from 'react';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport type {\n BackofficeListState,\n BackofficeRuntimeResolvedListFacetConfig,\n} from '@plumile/backoffice-core/types.js';\n\n/** Normalizes a router `location.search` string into URLSearchParams. */\nfunction normalizeSearch(value: string): URLSearchParams {\n if (value.trim() === '') {\n return new URLSearchParams();\n }\n return new URLSearchParams(value);\n}\n\ntype ReturnValue<Where extends Record<string, unknown>, Sort extends string> = {\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n};\n\n/** Keeps list state in sync with the URL search params for backoffice pages. */\nexport function useBackofficeListUrlState<\n Where extends Record<string, unknown>,\n Sort extends string,\n>(config: BackofficeRuntimeResolvedListFacetConfig): ReturnValue<Where, Sort> {\n const routing = useContext(RoutingContext);\n const { hash, pathname, search } = useLocation();\n const fallbackState = useMemo(() => {\n return {\n where: null,\n sort: null,\n };\n }, []);\n\n const state = useMemo(() => {\n if (config.listUrlCodec == null) {\n return fallbackState;\n }\n return config.listUrlCodec.parse(\n normalizeSearch(search),\n ) as BackofficeListState<Where, Sort>;\n }, [config.listUrlCodec, fallbackState, search]);\n\n const pushState = useCallback(\n (next: BackofficeListState<Where, Sort>) => {\n if (routing == null) {\n return;\n }\n if (config.listUrlCodec == null) {\n return;\n }\n\n const codec = config.listUrlCodec as unknown as {\n serialize: (state: BackofficeListState<Where, Sort>) => URLSearchParams;\n };\n const params = codec.serialize(next);\n const qs = params.toString();\n\n let nextSearch = '';\n if (qs !== '') {\n nextSearch = `?${qs}`;\n }\n\n startTransition(() => {\n routing.history.push({\n pathname,\n search: nextSearch,\n hash,\n });\n });\n },\n [config.listUrlCodec, hash, pathname, routing],\n );\n\n return { state, pushState };\n}\n"],"mappings":";;;;AAUA,SAAS,EAAgB,GAAgC;CAIvD,OAHI,EAAM,KAAK,MAAM,KACZ,IAAI,gBAAgB,IAEtB,IAAI,gBAAgB,CAAK;AAClC;AAQA,SAAgB,EAGd,GAA4E;CAC5E,IAAM,IAAU,EAAW,CAAc,GACnC,EAAE,SAAM,aAAU,cAAW,EAAY,GACzC,IAAgB,SACb;EACL,OAAO;EACP,MAAM;CACR,IACC,CAAC,CAAC;CA0CL,OAAO;EAAE,OAxCK,QACR,EAAO,gBAAgB,OAClB,IAEF,EAAO,aAAa,MACzB,EAAgB,CAAM,CACxB,GACC;GAAC,EAAO;GAAc;GAAe;EAAM,CAiCrC;EAAO,WA/BE,GACf,MAA2C;GAI1C,IAHI,KAAW,QAGX,EAAO,gBAAgB,MACzB;GAOF,IAAM,IAJQ,EAAO,aAGA,UAAU,CACpB,CAAA,CAAO,SAAS,GAEvB,IAAa;GAKjB,AAJI,MAAO,OACT,IAAa,IAAI,MAGnB,QAAsB;IACpB,EAAQ,QAAQ,KAAK;KACnB;KACA,QAAQ;KACR;IACF,CAAC;GACH,CAAC;EACH,GACA;GAAC,EAAO;GAAc;GAAM;GAAU;EAAO,CAG/B;CAAU;AAC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBackofficeSessionAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeSessionAuth.ts"],"sourcesContent":["import * as ReactRelay from 'react-relay';\nimport type { MutationParameters } from 'relay-runtime';\n\nimport type { LogoutResponse, LogoutVariables } from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeAuthLogoutConfig } from '../provider/useBackofficeLazyValue.js';\n\nconst { useMutation } = ReactRelay;\n\nconst toLogoutCleanupError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Logout cleanup failed.');\n};\n\nexport type BackofficeSessionAuth = {\n logout: () => Promise<void>;\n isLoading: boolean;\n};\n\nexport const useBackofficeSessionAuth = (): BackofficeSessionAuth => {\n const { auth: authConfig } = useBackofficeConfig();\n const auth = useBackofficeAuthLogoutConfig();\n\n type LogoutMutation = MutationParameters & {\n response: LogoutResponse;\n variables: LogoutVariables;\n };\n\n const [commitLogout, isLogoutInFlight] = useMutation<LogoutMutation>(\n auth.logoutMutation,\n );\n\n return {\n logout: async () => {\n return new Promise((resolve, reject) => {\n commitLogout({\n variables: {},\n onCompleted: () => {\n Promise.resolve(authConfig.lifecycle?.onLogoutSuccess?.()).then(\n () => {\n resolve();\n },\n (error: unknown) => {\n reject(toLogoutCleanupError(error));\n },\n );\n },\n onError: (error) => {\n if (error instanceof Error) {\n reject(error);\n return;\n }\n reject(new Error('Logout failed.'));\n },\n });\n });\n },\n isLoading: isLogoutInFlight,\n };\n};\n\nexport default useBackofficeSessionAuth;\n"],"mappings":";;;;AAOA,IAAM,EAAE,mBAAgB,GAElB,KAAwB,MACxB,aAAiB,QACZ,IAEF,gBAAI,MAAM,wBAAwB,GAQ9B,UAAwD;CACnE,IAAM,EAAE,MAAM,MAAe,EAAoB,GAQ3C,CAAC,GAAc,KAAoB,EAP5B,EAQX,EAAK,cACP;CAEA,OAAO;EACL,QAAQ,YACC,IAAI,SAAS,GAAS,MAAW;GACtC,EAAa;IACX,WAAW,CAAC;IACZ,mBAAmB;KACjB,QAAQ,QAAQ,EAAW,WAAW,kBAAkB,CAAC,EAAE,WACnD;MACJ,EAAQ;KACV,IACC,MAAmB;MAClB,EAAO,EAAqB,CAAK,CAAC;KACpC,CACF;IACF;IACA,UAAU,MAAU;KAClB,IAAI,aAAiB,OAAO;MAC1B,EAAO,CAAK;MACZ;KACF;KACA,EAAO,gBAAI,MAAM,gBAAgB,CAAC;IACpC;GACF,CAAC;EACH,CAAC;EAEH,WAAW;CACb;AACF"}
1
+ {"version":3,"file":"useBackofficeSessionAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeSessionAuth.ts"],"sourcesContent":["import * as ReactRelay from 'react-relay';\nimport type { MutationParameters } from 'relay-runtime';\n\nimport type { LogoutResponse, LogoutVariables } from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeAuthLogoutConfig } from '../provider/useBackofficeLazyValue.js';\n\nconst { useMutation } = ReactRelay;\n\nconst toLogoutCleanupError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Logout cleanup failed.');\n};\n\nexport type BackofficeSessionAuth = {\n logout: () => Promise<void>;\n isLoading: boolean;\n};\n\nexport const useBackofficeSessionAuth = (): BackofficeSessionAuth => {\n const { auth: authConfig } = useBackofficeConfig();\n const auth = useBackofficeAuthLogoutConfig();\n\n type LogoutMutation = MutationParameters & {\n response: LogoutResponse;\n variables: LogoutVariables;\n };\n\n const [commitLogout, isLogoutInFlight] = useMutation<LogoutMutation>(\n auth.logoutMutation,\n );\n\n return {\n logout: async () => {\n return new Promise((resolve, reject) => {\n commitLogout({\n variables: {},\n onCompleted: () => {\n Promise.resolve(authConfig.lifecycle?.onLogoutSuccess?.()).then(\n () => {\n resolve();\n },\n (error: unknown) => {\n reject(toLogoutCleanupError(error));\n },\n );\n },\n onError: (error) => {\n if (error instanceof Error) {\n reject(error);\n return;\n }\n reject(new Error('Logout failed.'));\n },\n });\n });\n },\n isLoading: isLogoutInFlight,\n };\n};\n\nexport default useBackofficeSessionAuth;\n"],"mappings":";;;;AAOA,IAAM,EAAE,mBAAgB,GAElB,KAAwB,MACxB,aAAiB,QACZ,IAEF,gBAAI,MAAM,wBAAwB,GAQ9B,UAAwD;CACnE,IAAM,EAAE,MAAM,MAAe,EAAoB,GAQ3C,CAAC,GAAc,KAAoB,EAP5B,EAQX,CAAA,CAAK,cACP;CAEA,OAAO;EACL,QAAQ,YACC,IAAI,SAAS,GAAS,MAAW;GACtC,EAAa;IACX,WAAW,CAAC;IACZ,mBAAmB;KACjB,QAAQ,QAAQ,EAAW,WAAW,kBAAkB,CAAC,CAAC,CAAC,WACnD;MACJ,EAAQ;KACV,IACC,MAAmB;MAClB,EAAO,EAAqB,CAAK,CAAC;KACpC,CACF;IACF;IACA,UAAU,MAAU;KAClB,IAAI,aAAiB,OAAO;MAC1B,EAAO,CAAK;MACZ;KACF;KACA,EAAO,gBAAI,MAAM,gBAAgB,CAAC;IACpC;GACF,CAAC;EACH,CAAC;EAEH,WAAW;CACb;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"useConditionalSubscription.js","names":[],"sources":["../../../src/hooks/useConditionalSubscription.ts"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLSubscriptionConfig, OperationType } from 'relay-runtime';\n\nimport {\n getRelayTransportSnapshot,\n subscribeRelayTransport,\n} from '../relay/environment.js';\n\ntype ConditionalOptions<T extends OperationType> = {\n enabled: boolean;\n deps?: readonly unknown[];\n getVariables?: () => T['variables'];\n};\n\ntype UseConditionalSubscriptionReturn = {\n active: boolean;\n completed: boolean;\n error: Error | null;\n};\n\ntype Hop = { dispose: () => void } | null;\n\nconst EMPTY_DEPS: readonly unknown[] = [];\n\n/** Resolve the Relay module regardless of whether the package exposes a default export shim. */\nfunction resolveRelayApi(): typeof ReactRelay {\n const relayDefault: unknown = Reflect.get(ReactRelay, 'default');\n if (relayDefault != null) {\n return relayDefault as typeof ReactRelay;\n }\n return ReactRelay;\n}\n\nconst relayApi = resolveRelayApi();\n\n/** Subscribe only when the caller enables the subscription and variables exist. */\nexport function useConditionalSubscription<T extends OperationType>(\n config: GraphQLSubscriptionConfig<T>,\n options: ConditionalOptions<T>,\n): UseConditionalSubscriptionReturn {\n const environment = relayApi.useRelayEnvironment();\n const [error, setError] = useState<Error | null>(null);\n const [isSubscribed, setIsSubscribed] = useState(false);\n const [completed, setCompleted] = useState(false);\n const transportGeneration = useSyncExternalStore(\n subscribeRelayTransport,\n () => {\n return getRelayTransportSnapshot().generation;\n },\n () => {\n return getRelayTransportSnapshot().generation;\n },\n );\n\n const { enabled = true, deps = EMPTY_DEPS, getVariables } = options;\n\n const resolveVariables = useCallback((): T['variables'] | null => {\n try {\n if (getVariables != null) {\n return getVariables();\n }\n return config.variables;\n } catch {\n return null;\n }\n }, [config.variables, getVariables]);\n\n const resolvedVariables = useMemo<T['variables'] | null>(() => {\n return resolveVariables();\n }, [resolveVariables]);\n\n const stableVarsString = useMemo(() => {\n if (resolvedVariables == null) {\n return null;\n }\n try {\n return JSON.stringify(resolvedVariables);\n } catch {\n return null;\n }\n }, [resolvedVariables]);\n\n const isEnabled = Boolean(enabled);\n const variables = resolvedVariables;\n const canSubscribe = isEnabled && variables != null;\n const active = canSubscribe && isSubscribed && error == null && !completed;\n\n const disposableRef = useRef<Hop>(null);\n\n useEffect(() => {\n let disposable: Hop = null;\n const variables = resolveVariables();\n\n if (isEnabled && variables != null) {\n setError(null);\n setCompleted(false);\n setIsSubscribed(true);\n\n disposable = relayApi.requestSubscription<T>(environment, {\n subscription: config.subscription,\n variables,\n cacheConfig: config.cacheConfig,\n configs: config.configs,\n onCompleted: () => {\n setCompleted(true);\n setIsSubscribed(false);\n config.onCompleted?.();\n },\n onError: (nextError) => {\n setError(nextError);\n setIsSubscribed(false);\n config.onError?.(nextError);\n },\n onNext: config.onNext,\n updater: config.updater,\n });\n\n disposableRef.current = disposable;\n }\n\n return () => {\n setIsSubscribed(false);\n if (disposable != null) {\n try {\n disposable.dispose();\n } catch {\n // ignore cleanup failures\n }\n }\n if (disposableRef.current === disposable) {\n disposableRef.current = null;\n }\n };\n }, [\n config,\n deps,\n environment,\n isEnabled,\n resolveVariables,\n stableVarsString,\n transportGeneration,\n ]);\n\n return { active, completed, error };\n}\n"],"mappings":";;;;AA8BA,IAAM,IAAiC,CAAC;AAGxC,SAAS,IAAqC;CAK5C,OAJ8B,QAAQ,IAAI,GAAY,SAClD,KAGG;AACT;AAEA,IAAM,IAAW,EAAgB;AAGjC,SAAgB,EACd,GACA,GACkC;CAClC,IAAM,IAAc,EAAS,oBAAoB,GAC3C,CAAC,GAAO,KAAY,EAAuB,IAAI,GAC/C,CAAC,GAAc,KAAmB,EAAS,EAAK,GAChD,CAAC,GAAW,KAAgB,EAAS,EAAK,GAC1C,IAAsB,EAC1B,SAES,EAA0B,EAAE,kBAG5B,EAA0B,EAAE,UAEvC,GAEM,EAAE,aAAU,IAAM,UAAO,GAAY,oBAAiB,GAEtD,IAAmB,QAAyC;EAChE,IAAI;GAIF,OAHI,KAAgB,OAGb,EAAO,YAFL,EAAa;EAGxB,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,EAAO,WAAW,CAAY,CAAC,GAE7B,IAAoB,QACjB,EAAiB,GACvB,CAAC,CAAgB,CAAC,GAEf,IAAmB,QAAc;EACrC,IAAI,KAAqB,MACvB,OAAO;EAET,IAAI;GACF,OAAO,KAAK,UAAU,CAAiB;EACzC,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,CAAiB,CAAC,GAEhB,IAAY,EAAQ,GAGpB,IADe,KAAa,KAAa,QAChB,KAAgB,KAAS,QAAQ,CAAC,GAE3D,IAAgB,EAAY,IAAI;CAwDtC,OAtDA,QAAgB;EACd,IAAI,IAAkB,MAChB,IAAY,EAAiB;EA6BnC,OA3BI,KAAa,KAAa,SAC5B,EAAS,IAAI,GACb,EAAa,EAAK,GAClB,EAAgB,EAAI,GAEpB,IAAa,EAAS,oBAAuB,GAAa;GACxD,cAAc,EAAO;GACrB;GACA,aAAa,EAAO;GACpB,SAAS,EAAO;GAChB,mBAAmB;IAGjB,AAFA,EAAa,EAAI,GACjB,EAAgB,EAAK,GACrB,EAAO,cAAc;GACvB;GACA,UAAU,MAAc;IAGtB,AAFA,EAAS,CAAS,GAClB,EAAgB,EAAK,GACrB,EAAO,UAAU,CAAS;GAC5B;GACA,QAAQ,EAAO;GACf,SAAS,EAAO;EAClB,CAAC,GAED,EAAc,UAAU,UAGb;GAEX,IADA,EAAgB,EAAK,GACjB,KAAc,MAChB,IAAI;IACF,EAAW,QAAQ;GACrB,QAAQ,CAER;GAEF,AAAI,EAAc,YAAY,MAC5B,EAAc,UAAU;EAE5B;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,GAEM;EAAE;EAAQ;EAAW;CAAM;AACpC"}
1
+ {"version":3,"file":"useConditionalSubscription.js","names":[],"sources":["../../../src/hooks/useConditionalSubscription.ts"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLSubscriptionConfig, OperationType } from 'relay-runtime';\n\nimport {\n getRelayTransportSnapshot,\n subscribeRelayTransport,\n} from '../relay/environment.js';\n\ntype ConditionalOptions<T extends OperationType> = {\n enabled: boolean;\n deps?: readonly unknown[];\n getVariables?: () => T['variables'];\n};\n\ntype UseConditionalSubscriptionReturn = {\n active: boolean;\n completed: boolean;\n error: Error | null;\n};\n\ntype Hop = { dispose: () => void } | null;\n\nconst EMPTY_DEPS: readonly unknown[] = [];\n\n/** Resolve the Relay module regardless of whether the package exposes a default export shim. */\nfunction resolveRelayApi(): typeof ReactRelay {\n const relayDefault: unknown = Reflect.get(ReactRelay, 'default');\n if (relayDefault != null) {\n return relayDefault as typeof ReactRelay;\n }\n return ReactRelay;\n}\n\nconst relayApi = resolveRelayApi();\n\n/** Subscribe only when the caller enables the subscription and variables exist. */\nexport function useConditionalSubscription<T extends OperationType>(\n config: GraphQLSubscriptionConfig<T>,\n options: ConditionalOptions<T>,\n): UseConditionalSubscriptionReturn {\n const environment = relayApi.useRelayEnvironment();\n const [error, setError] = useState<Error | null>(null);\n const [isSubscribed, setIsSubscribed] = useState(false);\n const [completed, setCompleted] = useState(false);\n const transportGeneration = useSyncExternalStore(\n subscribeRelayTransport,\n () => {\n return getRelayTransportSnapshot().generation;\n },\n () => {\n return getRelayTransportSnapshot().generation;\n },\n );\n\n const { enabled = true, deps = EMPTY_DEPS, getVariables } = options;\n\n const resolveVariables = useCallback((): T['variables'] | null => {\n try {\n if (getVariables != null) {\n return getVariables();\n }\n return config.variables;\n } catch {\n return null;\n }\n }, [config.variables, getVariables]);\n\n const resolvedVariables = useMemo<T['variables'] | null>(() => {\n return resolveVariables();\n }, [resolveVariables]);\n\n const stableVarsString = useMemo(() => {\n if (resolvedVariables == null) {\n return null;\n }\n try {\n return JSON.stringify(resolvedVariables);\n } catch {\n return null;\n }\n }, [resolvedVariables]);\n\n const isEnabled = Boolean(enabled);\n const variables = resolvedVariables;\n const canSubscribe = isEnabled && variables != null;\n const active = canSubscribe && isSubscribed && error == null && !completed;\n\n const disposableRef = useRef<Hop>(null);\n\n useEffect(() => {\n let disposable: Hop = null;\n const variables = resolveVariables();\n\n if (isEnabled && variables != null) {\n setError(null);\n setCompleted(false);\n setIsSubscribed(true);\n\n disposable = relayApi.requestSubscription<T>(environment, {\n subscription: config.subscription,\n variables,\n cacheConfig: config.cacheConfig,\n configs: config.configs,\n onCompleted: () => {\n setCompleted(true);\n setIsSubscribed(false);\n config.onCompleted?.();\n },\n onError: (nextError) => {\n setError(nextError);\n setIsSubscribed(false);\n config.onError?.(nextError);\n },\n onNext: config.onNext,\n updater: config.updater,\n });\n\n disposableRef.current = disposable;\n }\n\n return () => {\n setIsSubscribed(false);\n if (disposable != null) {\n try {\n disposable.dispose();\n } catch {\n // ignore cleanup failures\n }\n }\n if (disposableRef.current === disposable) {\n disposableRef.current = null;\n }\n };\n }, [\n config,\n deps,\n environment,\n isEnabled,\n resolveVariables,\n stableVarsString,\n transportGeneration,\n ]);\n\n return { active, completed, error };\n}\n"],"mappings":";;;;AA8BA,IAAM,IAAiC,CAAC;AAGxC,SAAS,IAAqC;CAK5C,OAJ8B,QAAQ,IAAI,GAAY,SAClD,KAGG;AACT;AAEA,IAAM,IAAW,EAAgB;AAGjC,SAAgB,EACd,GACA,GACkC;CAClC,IAAM,IAAc,EAAS,oBAAoB,GAC3C,CAAC,GAAO,KAAY,EAAuB,IAAI,GAC/C,CAAC,GAAc,KAAmB,EAAS,EAAK,GAChD,CAAC,GAAW,KAAgB,EAAS,EAAK,GAC1C,IAAsB,EAC1B,SAES,EAA0B,CAAC,CAAC,kBAG5B,EAA0B,CAAC,CAAC,UAEvC,GAEM,EAAE,aAAU,IAAM,UAAO,GAAY,oBAAiB,GAEtD,IAAmB,QAAyC;EAChE,IAAI;GAIF,OAHI,KAAgB,OAGb,EAAO,YAFL,EAAa;EAGxB,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,EAAO,WAAW,CAAY,CAAC,GAE7B,IAAoB,QACjB,EAAiB,GACvB,CAAC,CAAgB,CAAC,GAEf,IAAmB,QAAc;EACrC,IAAI,KAAqB,MACvB,OAAO;EAET,IAAI;GACF,OAAO,KAAK,UAAU,CAAiB;EACzC,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,CAAiB,CAAC,GAEhB,IAAY,EAAQ,GAGpB,IADe,KAAa,KAAa,QAChB,KAAgB,KAAS,QAAQ,CAAC,GAE3D,IAAgB,EAAY,IAAI;CAwDtC,OAtDA,QAAgB;EACd,IAAI,IAAkB,MAChB,IAAY,EAAiB;EA6BnC,OA3BI,KAAa,KAAa,SAC5B,EAAS,IAAI,GACb,EAAa,EAAK,GAClB,EAAgB,EAAI,GAEpB,IAAa,EAAS,oBAAuB,GAAa;GACxD,cAAc,EAAO;GACrB;GACA,aAAa,EAAO;GACpB,SAAS,EAAO;GAChB,mBAAmB;IAGjB,AAFA,EAAa,EAAI,GACjB,EAAgB,EAAK,GACrB,EAAO,cAAc;GACvB;GACA,UAAU,MAAc;IAGtB,AAFA,EAAS,CAAS,GAClB,EAAgB,EAAK,GACrB,EAAO,UAAU,CAAS;GAC5B;GACA,QAAQ,EAAO;GACf,SAAS,EAAO;EAClB,CAAC,GAED,EAAc,UAAU,UAGb;GAEX,IADA,EAAgB,EAAK,GACjB,KAAc,MAChB,IAAI;IACF,EAAW,QAAQ;GACrB,QAAQ,CAER;GAEF,AAAI,EAAc,YAAY,MAC5B,EAAc,UAAU;EAE5B;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,GAEM;EAAE;EAAQ;EAAW;CAAM;AACpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useSidebarGroupCollapse.js","names":[],"sources":["../../../src/hooks/useSidebarGroupCollapse.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\n\nexport type SidebarGroupCollapseState = Record<string, boolean | undefined>;\n\nexport type UseSidebarGroupCollapseInput = {\n groupIds: readonly string[];\n activeGroupId?: string | null;\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>;\n storageKey?: string;\n persist?: boolean;\n};\n\nconst readStoredState = (\n storageKey: string | undefined,\n): SidebarGroupCollapseState | null => {\n if (storageKey == null || typeof window === 'undefined') {\n return null;\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return null;\n }\n const parsed = JSON.parse(raw) as unknown;\n if (parsed == null || typeof parsed !== 'object') {\n return null;\n }\n const output: SidebarGroupCollapseState = {};\n Object.entries(parsed as Record<string, unknown>).forEach(\n ([key, value]) => {\n if (typeof value === 'boolean') {\n output[key] = value;\n }\n },\n );\n return output;\n } catch {\n return null;\n }\n};\n\nconst buildInitialState = (\n groupIds: readonly string[],\n activeGroupId?: string | null,\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>,\n): SidebarGroupCollapseState => {\n const state: SidebarGroupCollapseState = {};\n groupIds.forEach((groupId) => {\n state[groupId] = defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n if (activeGroupId != null && groupIds.includes(activeGroupId)) {\n state[activeGroupId] = false;\n }\n return state;\n};\n\nexport const useSidebarGroupCollapse = (\n input: UseSidebarGroupCollapseInput,\n): {\n collapsedByGroupId: SidebarGroupCollapseState;\n setCollapsed: (groupId: string, collapsed: boolean) => void;\n} => {\n const {\n activeGroupId,\n defaultCollapsedByGroupId,\n groupIds,\n persist = false,\n storageKey,\n } = input;\n\n const groupIdList = useMemo(() => {\n return [...groupIds];\n }, [groupIds]);\n\n const [collapsedByGroupId, setCollapsedByGroupId] =\n useState<SidebarGroupCollapseState>(() => {\n if (persist) {\n const stored = readStoredState(storageKey);\n if (stored != null) {\n return {\n ...buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n ),\n ...stored,\n };\n }\n }\n return buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n );\n });\n\n useEffect(() => {\n setCollapsedByGroupId((prev) => {\n const next: SidebarGroupCollapseState = {};\n\n groupIdList.forEach((groupId) => {\n const existing = prev[groupId];\n next[groupId] =\n existing ?? defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n\n if (activeGroupId != null && groupIdList.includes(activeGroupId)) {\n next[activeGroupId] = false;\n }\n\n return next;\n });\n }, [activeGroupId, defaultCollapsedByGroupId, groupIdList]);\n\n useEffect(() => {\n if (!persist || storageKey == null || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify(collapsedByGroupId),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [collapsedByGroupId, persist, storageKey]);\n\n useEffect(() => {\n if (activeGroupId == null) {\n return;\n }\n setCollapsedByGroupId((prev) => {\n if (prev[activeGroupId] === false) {\n return prev;\n }\n return {\n ...prev,\n [activeGroupId]: false,\n };\n });\n }, [activeGroupId]);\n\n const setCollapsed = useCallback((groupId: string, collapsed: boolean) => {\n setCollapsedByGroupId((prev) => {\n if (prev[groupId] === collapsed) {\n return prev;\n }\n return {\n ...prev,\n [groupId]: collapsed,\n };\n });\n }, []);\n\n return {\n collapsedByGroupId,\n setCollapsed,\n };\n};\n\nexport default useSidebarGroupCollapse;\n"],"mappings":";;AAYA,IAAM,KACJ,MACqC;CACrC,IAAI,KAAc,QAAQ,OAAO,SAAW,KAC1C,OAAO;CAET,IAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,CAAU;EAClD,IAAI,KAAO,MACT,OAAO;EAET,IAAM,IAAS,KAAK,MAAM,CAAG;EAC7B,IAAsB,OAAO,KAAW,aAApC,GACF,OAAO;EAET,IAAM,IAAoC,CAAC;EAQ3C,OAPA,OAAO,QAAQ,CAAiC,EAAE,SAC/C,CAAC,GAAK,OAAW;GAChB,AAAI,OAAO,KAAU,cACnB,EAAO,KAAO;EAElB,CACF,GACO;CACT,QAAQ;EACN,OAAO;CACT;AACF,GAEM,KACJ,GACA,GACA,MAC8B;CAC9B,IAAM,IAAmC,CAAC;CAO1C,OANA,EAAS,SAAS,MAAY;EAC5B,EAAM,KAAW,IAA4B,MAAY;CAC3D,CAAC,GACG,KAAiB,QAAQ,EAAS,SAAS,CAAa,MAC1D,EAAM,KAAiB,KAElB;AACT,GAEa,KACX,MAIG;CACH,IAAM,EACJ,kBACA,8BACA,aACA,aAAU,IACV,kBACE,GAEE,IAAc,QACX,CAAC,GAAG,CAAQ,GAClB,CAAC,CAAQ,CAAC,GAEP,CAAC,GAAoB,KACzB,QAA0C;EACxC,IAAI,GAAS;GACX,IAAM,IAAS,EAAgB,CAAU;GACzC,IAAI,KAAU,MACZ,OAAO;IACL,GAAG,EACD,GACA,GACA,CACF;IACA,GAAG;GACL;EAEJ;EACA,OAAO,EACL,GACA,GACA,CACF;CACF,CAAC;CA6DH,OA3DA,QAAgB;EACd,GAAuB,MAAS;GAC9B,IAAM,IAAkC,CAAC;GAYzC,OAVA,EAAY,SAAS,MAAY;IAE/B,EAAK,KADY,EAAK,MAER,IAA4B,MAAY;GACxD,CAAC,GAEG,KAAiB,QAAQ,EAAY,SAAS,CAAa,MAC7D,EAAK,KAAiB,KAGjB;EACT,CAAC;CACH,GAAG;EAAC;EAAe;EAA2B;CAAW,CAAC,GAE1D,QAAgB;EACV,OAAC,KAAW,KAAc,QAAQ,OAAO,SAAW,MAGxD,IAAI;GACF,OAAO,aAAa,QAClB,GACA,KAAK,UAAU,CAAkB,CACnC;EACF,QAAQ,CAER;CACF,GAAG;EAAC;EAAoB;EAAS;CAAU,CAAC,GAE5C,QAAgB;EACV,KAAiB,QAGrB,GAAuB,MACjB,EAAK,OAAmB,KACnB,IAEF;GACL,GAAG;IACF,IAAgB;EACnB,CACD;CACH,GAAG,CAAC,CAAa,CAAC,GAcX;EACL;EACA,cAdmB,GAAa,GAAiB,MAAuB;GACxE,GAAuB,MACjB,EAAK,OAAa,IACb,IAEF;IACL,GAAG;KACF,IAAU;GACb,CACD;EACH,GAAG,CAAC,CAIF;CACF;AACF"}
1
+ {"version":3,"file":"useSidebarGroupCollapse.js","names":[],"sources":["../../../src/hooks/useSidebarGroupCollapse.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\n\nexport type SidebarGroupCollapseState = Record<string, boolean | undefined>;\n\nexport type UseSidebarGroupCollapseInput = {\n groupIds: readonly string[];\n activeGroupId?: string | null;\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>;\n storageKey?: string;\n persist?: boolean;\n};\n\nconst readStoredState = (\n storageKey: string | undefined,\n): SidebarGroupCollapseState | null => {\n if (storageKey == null || typeof window === 'undefined') {\n return null;\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return null;\n }\n const parsed = JSON.parse(raw) as unknown;\n if (parsed == null || typeof parsed !== 'object') {\n return null;\n }\n const output: SidebarGroupCollapseState = {};\n Object.entries(parsed as Record<string, unknown>).forEach(\n ([key, value]) => {\n if (typeof value === 'boolean') {\n output[key] = value;\n }\n },\n );\n return output;\n } catch {\n return null;\n }\n};\n\nconst buildInitialState = (\n groupIds: readonly string[],\n activeGroupId?: string | null,\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>,\n): SidebarGroupCollapseState => {\n const state: SidebarGroupCollapseState = {};\n groupIds.forEach((groupId) => {\n state[groupId] = defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n if (activeGroupId != null && groupIds.includes(activeGroupId)) {\n state[activeGroupId] = false;\n }\n return state;\n};\n\nexport const useSidebarGroupCollapse = (\n input: UseSidebarGroupCollapseInput,\n): {\n collapsedByGroupId: SidebarGroupCollapseState;\n setCollapsed: (groupId: string, collapsed: boolean) => void;\n} => {\n const {\n activeGroupId,\n defaultCollapsedByGroupId,\n groupIds,\n persist = false,\n storageKey,\n } = input;\n\n const groupIdList = useMemo(() => {\n return [...groupIds];\n }, [groupIds]);\n\n const [collapsedByGroupId, setCollapsedByGroupId] =\n useState<SidebarGroupCollapseState>(() => {\n if (persist) {\n const stored = readStoredState(storageKey);\n if (stored != null) {\n return {\n ...buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n ),\n ...stored,\n };\n }\n }\n return buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n );\n });\n\n useEffect(() => {\n setCollapsedByGroupId((prev) => {\n const next: SidebarGroupCollapseState = {};\n\n groupIdList.forEach((groupId) => {\n const existing = prev[groupId];\n next[groupId] =\n existing ?? defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n\n if (activeGroupId != null && groupIdList.includes(activeGroupId)) {\n next[activeGroupId] = false;\n }\n\n return next;\n });\n }, [activeGroupId, defaultCollapsedByGroupId, groupIdList]);\n\n useEffect(() => {\n if (!persist || storageKey == null || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify(collapsedByGroupId),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [collapsedByGroupId, persist, storageKey]);\n\n useEffect(() => {\n if (activeGroupId == null) {\n return;\n }\n setCollapsedByGroupId((prev) => {\n if (prev[activeGroupId] === false) {\n return prev;\n }\n return {\n ...prev,\n [activeGroupId]: false,\n };\n });\n }, [activeGroupId]);\n\n const setCollapsed = useCallback((groupId: string, collapsed: boolean) => {\n setCollapsedByGroupId((prev) => {\n if (prev[groupId] === collapsed) {\n return prev;\n }\n return {\n ...prev,\n [groupId]: collapsed,\n };\n });\n }, []);\n\n return {\n collapsedByGroupId,\n setCollapsed,\n };\n};\n\nexport default useSidebarGroupCollapse;\n"],"mappings":";;AAYA,IAAM,KACJ,MACqC;CACrC,IAAI,KAAc,QAAQ,OAAO,SAAW,KAC1C,OAAO;CAET,IAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,CAAU;EAClD,IAAI,KAAO,MACT,OAAO;EAET,IAAM,IAAS,KAAK,MAAM,CAAG;EAC7B,IAAsB,OAAO,KAAW,aAApC,GACF,OAAO;EAET,IAAM,IAAoC,CAAC;EAQ3C,OAPA,OAAO,QAAQ,CAAiC,CAAC,CAAC,SAC/C,CAAC,GAAK,OAAW;GAChB,AAAI,OAAO,KAAU,cACnB,EAAO,KAAO;EAElB,CACF,GACO;CACT,QAAQ;EACN,OAAO;CACT;AACF,GAEM,KACJ,GACA,GACA,MAC8B;CAC9B,IAAM,IAAmC,CAAC;CAO1C,OANA,EAAS,SAAS,MAAY;EAC5B,EAAM,KAAW,IAA4B,MAAY;CAC3D,CAAC,GACG,KAAiB,QAAQ,EAAS,SAAS,CAAa,MAC1D,EAAM,KAAiB,KAElB;AACT,GAEa,KACX,MAIG;CACH,IAAM,EACJ,kBACA,8BACA,aACA,aAAU,IACV,kBACE,GAEE,IAAc,QACX,CAAC,GAAG,CAAQ,GAClB,CAAC,CAAQ,CAAC,GAEP,CAAC,GAAoB,KACzB,QAA0C;EACxC,IAAI,GAAS;GACX,IAAM,IAAS,EAAgB,CAAU;GACzC,IAAI,KAAU,MACZ,OAAO;IACL,GAAG,EACD,GACA,GACA,CACF;IACA,GAAG;GACL;EAEJ;EACA,OAAO,EACL,GACA,GACA,CACF;CACF,CAAC;CA6DH,OA3DA,QAAgB;EACd,GAAuB,MAAS;GAC9B,IAAM,IAAkC,CAAC;GAYzC,OAVA,EAAY,SAAS,MAAY;IAE/B,EAAK,KADY,EAAK,MAER,IAA4B,MAAY;GACxD,CAAC,GAEG,KAAiB,QAAQ,EAAY,SAAS,CAAa,MAC7D,EAAK,KAAiB,KAGjB;EACT,CAAC;CACH,GAAG;EAAC;EAAe;EAA2B;CAAW,CAAC,GAE1D,QAAgB;EACV,OAAC,KAAW,KAAc,QAAQ,OAAO,SAAW,MAGxD,IAAI;GACF,OAAO,aAAa,QAClB,GACA,KAAK,UAAU,CAAkB,CACnC;EACF,QAAQ,CAER;CACF,GAAG;EAAC;EAAoB;EAAS;CAAU,CAAC,GAE5C,QAAgB;EACV,KAAiB,QAGrB,GAAuB,MACjB,EAAK,OAAmB,KACnB,IAEF;GACL,GAAG;IACF,IAAgB;EACnB,CACD;CACH,GAAG,CAAC,CAAa,CAAC,GAcX;EACL;EACA,cAdmB,GAAa,GAAiB,MAAuB;GACxE,GAAuB,MACjB,EAAK,OAAa,IACb,IAEF;IACL,GAAG;KACF,IAAU;GACb,CACD;EACH,GAAG,CAAC,CAIF;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"createI18nInstance.js","names":[],"sources":["../../../src/i18n/createI18nInstance.ts"],"sourcesContent":["import { createInstance, type i18n, type InitOptions } from 'i18next';\nimport LanguageDetector, {\n type DetectorOptions,\n} from 'i18next-browser-languagedetector';\nimport { initReactI18next } from 'react-i18next';\n\ntype InitOptionsWithDetection = Omit<\n InitOptions,\n 'resources' | 'lng' | 'fallbackLng'\n> & {\n detection?: DetectorOptions;\n};\n\ntype InitConfig = InitOptions & {\n detection?: DetectorOptions;\n};\n\nexport interface CreateI18nOptions {\n resources: NonNullable<InitOptions['resources']>;\n lng?: InitOptions['lng'];\n fallbackLng?: InitOptions['fallbackLng'];\n initOptions?: InitOptionsWithDetection;\n instance?: i18n;\n useLanguageDetector?: boolean;\n detection?: DetectorOptions;\n}\n\nconst DEFAULT_NUMBER_OPTIONS = { maximumFractionDigits: 2 };\nconst DEFAULT_CURRENCY_OPTIONS = {\n style: 'currency',\n currency: 'USD',\n maximumFractionDigits: 2,\n} as const;\nconst DEFAULT_DATE_OPTIONS = { dateStyle: 'medium' } as const;\nconst DEFAULT_DATE_TIME_OPTIONS = {\n dateStyle: 'medium',\n timeStyle: 'short',\n} as const;\nconst DEFAULT_PERCENT_OPTIONS = { style: 'percent' } as const;\n\n/** Returns the best locale value from i18next's language list. */\nfunction getLocale(lng: string | string[] | undefined): string | undefined {\n if (Array.isArray(lng)) {\n return lng[0];\n }\n return lng;\n}\n\n/** Stringify interpolation values while avoiding Object.prototype defaults. */\nfunction stringifyValue(value: unknown): string {\n if (value == null) {\n return '';\n }\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n typeof value === 'bigint'\n ) {\n return String(value);\n }\n if (typeof value === 'symbol') {\n return value.toString();\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '';\n }\n}\n\n/** Format interpolated values using Intl based on the i18n format token. */\nfunction formatValue(\n value: unknown,\n format: string | undefined,\n lng: string | string[] | undefined,\n): string {\n if (format == null) {\n return stringifyValue(value);\n }\n\n const locale = getLocale(lng);\n\n if (format === 'number' && typeof value === 'number') {\n return new Intl.NumberFormat(locale, DEFAULT_NUMBER_OPTIONS).format(value);\n }\n\n if (format === 'currency' && typeof value === 'number') {\n return new Intl.NumberFormat(locale, DEFAULT_CURRENCY_OPTIONS).format(\n value,\n );\n }\n\n if (format === 'percent' && typeof value === 'number') {\n return new Intl.NumberFormat(locale, DEFAULT_PERCENT_OPTIONS).format(value);\n }\n\n if ((format === 'date' || format === 'datetime') && value != null) {\n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === 'string' || typeof value === 'number') {\n date = new Date(value);\n } else {\n date = new Date(stringifyValue(value));\n }\n if (!Number.isNaN(date.getTime())) {\n if (format === 'date') {\n return new Intl.DateTimeFormat(locale, DEFAULT_DATE_OPTIONS).format(\n date,\n );\n }\n return new Intl.DateTimeFormat(locale, DEFAULT_DATE_TIME_OPTIONS).format(\n date,\n );\n }\n }\n\n return stringifyValue(value);\n}\n\n/**\n * Create and initialize an i18next instance configured for React.\n * Each frontend can call this helper with its own resource bundles.\n */\nexport async function createI18nInstance(\n options: CreateI18nOptions,\n): Promise<i18n> {\n const {\n resources,\n lng,\n fallbackLng = 'en',\n initOptions = {},\n instance = createInstance(),\n useLanguageDetector = false,\n detection,\n } = options;\n\n const { interpolation, ...restInitOptions } = initOptions;\n\n if (useLanguageDetector) {\n instance.use(LanguageDetector);\n }\n instance.use(initReactI18next);\n\n try {\n const initConfig: InitConfig = {\n ...restInitOptions,\n resources,\n fallbackLng,\n interpolation: {\n escapeValue: false,\n ...interpolation,\n },\n };\n if (lng != null) {\n initConfig.lng = lng;\n }\n\n const detectionOptions = detection ?? initOptions.detection;\n if (useLanguageDetector && detectionOptions != null) {\n initConfig.detection = detectionOptions;\n }\n\n await instance.init(initConfig);\n\n const { formatter } = instance.services;\n if (formatter != null) {\n formatter.add('number', (value, lng) => {\n return formatValue(value, 'number', lng);\n });\n formatter.add('currency', (value, lng) => {\n return formatValue(value, 'currency', lng);\n });\n formatter.add('percent', (value, lng) => {\n return formatValue(value, 'percent', lng);\n });\n formatter.add('date', (value, lng) => {\n return formatValue(value, 'date', lng);\n });\n formatter.add('datetime', (value, lng) => {\n return formatValue(value, 'datetime', lng);\n });\n }\n } catch {\n // Swallow initialization errors to avoid blocking the UI.\n // Callers can inspect the instance for diagnostics if needed.\n }\n\n return instance;\n}\n\nexport const __test = {\n getLocale,\n stringifyValue,\n formatValue,\n} as const;\n"],"mappings":"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"}
1
+ {"version":3,"file":"createI18nInstance.js","names":[],"sources":["../../../src/i18n/createI18nInstance.ts"],"sourcesContent":["import { createInstance, type i18n, type InitOptions } from 'i18next';\nimport LanguageDetector, {\n type DetectorOptions,\n} from 'i18next-browser-languagedetector';\nimport { initReactI18next } from 'react-i18next';\n\ntype InitOptionsWithDetection = Omit<\n InitOptions,\n 'resources' | 'lng' | 'fallbackLng'\n> & {\n detection?: DetectorOptions;\n};\n\ntype InitConfig = InitOptions & {\n detection?: DetectorOptions;\n};\n\nexport interface CreateI18nOptions {\n resources: NonNullable<InitOptions['resources']>;\n lng?: InitOptions['lng'];\n fallbackLng?: InitOptions['fallbackLng'];\n initOptions?: InitOptionsWithDetection;\n instance?: i18n;\n useLanguageDetector?: boolean;\n detection?: DetectorOptions;\n}\n\nconst DEFAULT_NUMBER_OPTIONS = { maximumFractionDigits: 2 };\nconst DEFAULT_CURRENCY_OPTIONS = {\n style: 'currency',\n currency: 'USD',\n maximumFractionDigits: 2,\n} as const;\nconst DEFAULT_DATE_OPTIONS = { dateStyle: 'medium' } as const;\nconst DEFAULT_DATE_TIME_OPTIONS = {\n dateStyle: 'medium',\n timeStyle: 'short',\n} as const;\nconst DEFAULT_PERCENT_OPTIONS = { style: 'percent' } as const;\n\n/** Returns the best locale value from i18next's language list. */\nfunction getLocale(lng: string | string[] | undefined): string | undefined {\n if (Array.isArray(lng)) {\n return lng[0];\n }\n return lng;\n}\n\n/** Stringify interpolation values while avoiding Object.prototype defaults. */\nfunction stringifyValue(value: unknown): string {\n if (value == null) {\n return '';\n }\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n typeof value === 'bigint'\n ) {\n return String(value);\n }\n if (typeof value === 'symbol') {\n return value.toString();\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '';\n }\n}\n\n/** Format interpolated values using Intl based on the i18n format token. */\nfunction formatValue(\n value: unknown,\n format: string | undefined,\n lng: string | string[] | undefined,\n): string {\n if (format == null) {\n return stringifyValue(value);\n }\n\n const locale = getLocale(lng);\n\n if (format === 'number' && typeof value === 'number') {\n return new Intl.NumberFormat(locale, DEFAULT_NUMBER_OPTIONS).format(value);\n }\n\n if (format === 'currency' && typeof value === 'number') {\n return new Intl.NumberFormat(locale, DEFAULT_CURRENCY_OPTIONS).format(\n value,\n );\n }\n\n if (format === 'percent' && typeof value === 'number') {\n return new Intl.NumberFormat(locale, DEFAULT_PERCENT_OPTIONS).format(value);\n }\n\n if ((format === 'date' || format === 'datetime') && value != null) {\n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === 'string' || typeof value === 'number') {\n date = new Date(value);\n } else {\n date = new Date(stringifyValue(value));\n }\n if (!Number.isNaN(date.getTime())) {\n if (format === 'date') {\n return new Intl.DateTimeFormat(locale, DEFAULT_DATE_OPTIONS).format(\n date,\n );\n }\n return new Intl.DateTimeFormat(locale, DEFAULT_DATE_TIME_OPTIONS).format(\n date,\n );\n }\n }\n\n return stringifyValue(value);\n}\n\n/**\n * Create and initialize an i18next instance configured for React.\n * Each frontend can call this helper with its own resource bundles.\n */\nexport async function createI18nInstance(\n options: CreateI18nOptions,\n): Promise<i18n> {\n const {\n resources,\n lng,\n fallbackLng = 'en',\n initOptions = {},\n instance = createInstance(),\n useLanguageDetector = false,\n detection,\n } = options;\n\n const { interpolation, ...restInitOptions } = initOptions;\n\n if (useLanguageDetector) {\n instance.use(LanguageDetector);\n }\n instance.use(initReactI18next);\n\n try {\n const initConfig: InitConfig = {\n ...restInitOptions,\n resources,\n fallbackLng,\n interpolation: {\n escapeValue: false,\n ...interpolation,\n },\n };\n if (lng != null) {\n initConfig.lng = lng;\n }\n\n const detectionOptions = detection ?? initOptions.detection;\n if (useLanguageDetector && detectionOptions != null) {\n initConfig.detection = detectionOptions;\n }\n\n await instance.init(initConfig);\n\n const { formatter } = instance.services;\n if (formatter != null) {\n formatter.add('number', (value, lng) => {\n return formatValue(value, 'number', lng);\n });\n formatter.add('currency', (value, lng) => {\n return formatValue(value, 'currency', lng);\n });\n formatter.add('percent', (value, lng) => {\n return formatValue(value, 'percent', lng);\n });\n formatter.add('date', (value, lng) => {\n return formatValue(value, 'date', lng);\n });\n formatter.add('datetime', (value, lng) => {\n return formatValue(value, 'datetime', lng);\n });\n }\n } catch {\n // Swallow initialization errors to avoid blocking the UI.\n // Callers can inspect the instance for diagnostics if needed.\n }\n\n return instance;\n}\n\nexport const __test = {\n getLocale,\n stringifyValue,\n formatValue,\n} as const;\n"],"mappings":"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"}