@plumile/backoffice-react 0.1.82 → 0.1.83

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 (51) hide show
  1. package/lib/esm/{AcceptInvitationScreen-DJkNNx49.js → AcceptInvitationScreen-5-0EtE15.js} +4 -4
  2. package/lib/esm/{AcceptInvitationScreen-DJkNNx49.js.map → AcceptInvitationScreen-5-0EtE15.js.map} +1 -1
  3. package/lib/esm/{AuthPanel-Co626p7A.js → AuthPanel-DiHejPoq.js} +2 -2
  4. package/lib/esm/{AuthPanel-Co626p7A.js.map → AuthPanel-DiHejPoq.js.map} +1 -1
  5. package/lib/esm/{BackofficeAcceptInvitationPage-BQfDMSux.js → BackofficeAcceptInvitationPage-FPbn31YK.js} +6 -6
  6. package/lib/esm/{BackofficeAcceptInvitationPage-BQfDMSux.js.map → BackofficeAcceptInvitationPage-FPbn31YK.js.map} +1 -1
  7. package/lib/esm/{BackofficeDashboardPage-B5_YC1ZL.js → BackofficeDashboardPage-C7lIVeA1.js} +3 -3
  8. package/lib/esm/{BackofficeDashboardPage-B5_YC1ZL.js.map → BackofficeDashboardPage-C7lIVeA1.js.map} +1 -1
  9. package/lib/esm/{BackofficeDetailPayload-CbsZKnw6.js → BackofficeDetailPayload-iVx66o_6.js} +4 -4
  10. package/lib/esm/{BackofficeDetailPayload-CbsZKnw6.js.map → BackofficeDetailPayload-iVx66o_6.js.map} +1 -1
  11. package/lib/esm/{BackofficeEntityActionFormDialog-BzKi1eyv.js → BackofficeEntityActionFormDialog-V4QXnvpy.js} +18 -18
  12. package/lib/esm/{BackofficeEntityActionFormDialog-BzKi1eyv.js.map → BackofficeEntityActionFormDialog-V4QXnvpy.js.map} +1 -1
  13. package/lib/esm/{BackofficeEntityDetailPage-CE4tl5ZJ.js → BackofficeEntityDetailPage-BljQmWsw.js} +10 -10
  14. package/lib/esm/{BackofficeEntityDetailPage-CE4tl5ZJ.js.map → BackofficeEntityDetailPage-BljQmWsw.js.map} +1 -1
  15. package/lib/esm/{BackofficeEntityListPage-CtLI15-L.js → BackofficeEntityListPage-BneDsGo-.js} +6 -6
  16. package/lib/esm/{BackofficeEntityListPage-CtLI15-L.js.map → BackofficeEntityListPage-BneDsGo-.js.map} +1 -1
  17. package/lib/esm/{BackofficeLayoutPage-DpvTzwtK.js → BackofficeLayoutPage-Da4y2B0i.js} +5 -5
  18. package/lib/esm/{BackofficeLayoutPage-DpvTzwtK.js.map → BackofficeLayoutPage-Da4y2B0i.js.map} +1 -1
  19. package/lib/esm/{BackofficeLoginPage-GKVdZndS.js → BackofficeLoginPage-Dc61SyMV.js} +6 -6
  20. package/lib/esm/{BackofficeLoginPage-GKVdZndS.js.map → BackofficeLoginPage-Dc61SyMV.js.map} +1 -1
  21. package/lib/esm/{BackofficePasswordResetCompletePage-CCQJYK9S.js → BackofficePasswordResetCompletePage-CvoHqhBS.js} +4 -4
  22. package/lib/esm/{BackofficePasswordResetCompletePage-CCQJYK9S.js.map → BackofficePasswordResetCompletePage-CvoHqhBS.js.map} +1 -1
  23. package/lib/esm/{BackofficePasswordResetRequestPage-Df8mcLkC.js → BackofficePasswordResetRequestPage-DDNcCf3_.js} +4 -4
  24. package/lib/esm/{BackofficePasswordResetRequestPage-Df8mcLkC.js.map → BackofficePasswordResetRequestPage-DDNcCf3_.js.map} +1 -1
  25. package/lib/esm/{BackofficeRightPageLayout-D7QRE8KZ.js → BackofficeRightPageLayout-F8ipegrl.js} +3 -3
  26. package/lib/esm/{BackofficeRightPageLayout-D7QRE8KZ.js.map → BackofficeRightPageLayout-F8ipegrl.js.map} +1 -1
  27. package/lib/esm/{BackofficeVerifyEmailPage-CtqLzXAD.js → BackofficeVerifyEmailPage-BSTtLXdx.js} +3 -3
  28. package/lib/esm/{BackofficeVerifyEmailPage-CtqLzXAD.js.map → BackofficeVerifyEmailPage-BSTtLXdx.js.map} +1 -1
  29. package/lib/esm/{EntityFilterValue-Bn9VGr2M.js → EntityFilterValue-B5ZGHO_u.js} +2 -2
  30. package/lib/esm/{EntityFilterValue-Bn9VGr2M.js.map → EntityFilterValue-B5ZGHO_u.js.map} +1 -1
  31. package/lib/esm/{EntityIdPickerDialog-D_qAlrU6.js → EntityIdPickerDialog-DbTnDU4v.js} +3 -3
  32. package/lib/esm/{EntityIdPickerDialog-D_qAlrU6.js.map → EntityIdPickerDialog-DbTnDU4v.js.map} +1 -1
  33. package/lib/esm/{LazyBackofficeEntityActionFormDialog-DndjG4kV.js → LazyBackofficeEntityActionFormDialog-BE3wVfU6.js} +5 -5
  34. package/lib/esm/{LazyBackofficeEntityActionFormDialog-DndjG4kV.js.map → LazyBackofficeEntityActionFormDialog-BE3wVfU6.js.map} +1 -1
  35. package/lib/esm/{PasswordResetCompleteScreen-DdJsdKMI.js → PasswordResetCompleteScreen-B0P_tZg2.js} +3 -3
  36. package/lib/esm/{PasswordResetCompleteScreen-DdJsdKMI.js.map → PasswordResetCompleteScreen-B0P_tZg2.js.map} +1 -1
  37. package/lib/esm/{PasswordResetRequestScreen-DBIHOmsl.js → PasswordResetRequestScreen-p9s0dblR.js} +3 -3
  38. package/lib/esm/{PasswordResetRequestScreen-DBIHOmsl.js.map → PasswordResetRequestScreen-p9s0dblR.js.map} +1 -1
  39. package/lib/esm/{VerifyEmailScreen-C9rfi3q8.js → VerifyEmailScreen--9lxOGlW.js} +2 -2
  40. package/lib/esm/{VerifyEmailScreen-C9rfi3q8.js.map → VerifyEmailScreen--9lxOGlW.js.map} +1 -1
  41. package/lib/esm/backoffice-react.js +20 -20
  42. package/lib/esm/loginPage.css-CBJ1Ozm5.js +12 -0
  43. package/lib/esm/{loginPage.css-4M4PrzUn.js.map → loginPage.css-CBJ1Ozm5.js.map} +1 -1
  44. package/lib/esm/{synchronizeAuthStatusQuery-Bb5wh5rF.js → synchronizeAuthStatusQuery-Dr6AEFhi.js} +4 -4
  45. package/lib/esm/{synchronizeAuthStatusQuery-Bb5wh5rF.js.map → synchronizeAuthStatusQuery-Dr6AEFhi.js.map} +1 -1
  46. package/lib/esm/{useAuth-tQWc1NnB.js → useAuth-CjdysxLB.js} +2 -2
  47. package/lib/esm/{useAuth-tQWc1NnB.js.map → useAuth-CjdysxLB.js.map} +1 -1
  48. package/lib/esm/{useBackofficeAuth-BUrTeBOK.js → useBackofficeAuth-BshabGXc.js} +2 -2
  49. package/lib/esm/{useBackofficeAuth-BUrTeBOK.js.map → useBackofficeAuth-BshabGXc.js.map} +1 -1
  50. package/package.json +5 -5
  51. package/lib/esm/loginPage.css-4M4PrzUn.js +0 -12
@@ -1 +1 @@
1
- {"version":3,"file":"LazyBackofficeEntityActionFormDialog-DndjG4kV.js","names":[],"sources":["../../src/hooks/useBackofficeLoadMore.ts","../../src/hooks/useBackofficeListRefetch.ts","../../src/components/backoffice/scaffolds/backofficeEntityListScaffold.css.ts","../../src/components/backoffice/scaffolds/BackofficeEntityListScaffold.tsx","../../src/components/backoffice/actions/LazyBackofficeEntityActionFormDialog.tsx"],"sourcesContent":["import { startTransition, useCallback } from 'react';\n\ntype Params = {\n hasNext: boolean;\n isLoadingNext: boolean;\n loadNext: (count: number) => void;\n count: number;\n};\n\n/**\n * Wraps Relay `loadNext()` with consistent guards and `startTransition()`.\n */\nexport function useBackofficeLoadMore({\n hasNext,\n isLoadingNext,\n loadNext,\n count,\n}: Params): () => void {\n return useCallback(() => {\n if (!hasNext || isLoadingNext) {\n return;\n }\n\n startTransition(() => {\n loadNext(count);\n });\n }, [count, hasNext, isLoadingNext, loadNext]);\n}\n","import { useCallback, useEffect, useRef } from 'react';\nimport type { FetchPolicy } from 'relay-runtime';\n\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficeListVariables } from '@plumile/backoffice-core/types.js';\n\ntype RefetchFn<TVariables> = (\n vars: TVariables,\n opts: { fetchPolicy: FetchPolicy },\n) => void;\n\ntype Params<Where, Sort extends string, Variables> = {\n refetch: RefetchFn<Variables>;\n variables: BackofficeListVariables<Where, Sort>;\n defaults: BackofficeListVariables<Where, Sort>;\n fetchPolicy: FetchPolicy;\n buildVariables?: (input: BackofficeListVariables<Where, Sort>) => Variables;\n};\n\n/**\n * Standardizes refetch behavior for backoffice list components:\n * - Refetches when list URL state changes (where/sort/count), gated by a stable key.\n * - Exposes a manual refresh callback using the same variables.\n *\n * This hook must not call Relay hooks (`useFragment`, `usePaginationFragment`, ...).\n */\nexport function useBackofficeListRefetch<\n Where,\n Sort extends string,\n Variables extends Record<string, unknown>,\n>({\n refetch,\n variables,\n defaults,\n fetchPolicy,\n buildVariables,\n}: Params<Where, Sort, Variables>): { onRefresh: () => void } {\n const lastRefetchKeyRef = useRef<string | null>(\n stableListVariablesKey({\n where: defaults.where,\n sort: defaults.sort,\n count: defaults.count,\n }),\n );\n\n const resolveVariables = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n if (buildVariables != null) {\n return buildVariables(input);\n }\n return input as unknown as Variables;\n },\n [buildVariables],\n );\n\n useEffect(() => {\n const key = stableListVariablesKey({\n where: variables.where,\n sort: variables.sort,\n count: variables.count,\n });\n if (lastRefetchKeyRef.current === key) {\n return;\n }\n lastRefetchKeyRef.current = key;\n\n const nextVariables = resolveVariables({ ...variables, cursor: null });\n refetch(nextVariables, { fetchPolicy });\n }, [fetchPolicy, refetch, resolveVariables, variables]);\n\n const onRefresh = useCallback(() => {\n const nextVariables = resolveVariables({ ...variables, cursor: null });\n refetch(nextVariables, { fetchPolicy });\n }, [fetchPolicy, refetch, resolveVariables, variables]);\n\n return { onRefresh };\n}\n","import { sprinkles } from '@plumile/ui';\n\nexport const controlsRow = sprinkles({\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 2,\n});\n\nexport const filterInput = sprinkles({\n width: 72,\n maxWidth: 'full',\n});\n\nexport const embeddedContainer = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n});\n\nexport const embeddedHeader = sprinkles({\n fontSize: 'base',\n fontWeight: 'semibold',\n color: 'text',\n});\n","/* eslint-disable no-ternary */\nimport {\n type JSX,\n type ReactNode,\n useCallback,\n useMemo,\n useState,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { useTranslation } from 'react-i18next';\nimport {\n BackofficeEmptyState,\n BackofficeFilterDrawer,\n BackofficeFilterField,\n BackofficeLoadMore,\n BackofficePageHeader,\n BackofficeTableSkeleton,\n BackofficeTableToolbar,\n BackofficeVirtualizedConnectionTable,\n Button,\n FilterChipRow,\n GlobalSearchInput,\n InlineBanner,\n ListPageTemplate,\n SimpleSelect,\n type FilterChip,\n type DataTableColumn,\n type GetRowId,\n denseTableClass,\n} from '@plumile/ui';\n\nimport {\n readWhereValue,\n setWhereValue,\n} from '@plumile/backoffice-core/filters/where.js';\nimport type {\n BackofficeFilterSpec,\n BackofficeListState,\n BackofficePickerScope,\n BackofficeResolvedListFacetConfig,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\nimport {\n EntityFilterValue,\n EntityFilterValueText,\n} from '../filters/EntityFilterValue.js';\nimport { EntityIdPickerDialog } from '../pickers/EntityIdPickerDialog.js';\nimport { EntityIdFilterField } from '../filters/EntityIdFilterField.js';\nimport { BackofficeListFilterProvider } from './BackofficeListFilterContext.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './backofficeEntityListScaffold.css.js';\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nconst getFilterValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n where: Where | null,\n): unknown => {\n if (filter.fromGraphQL != null && where != null) {\n return filter.fromGraphQL(where);\n }\n\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n return readWhereValue(where, key, filter.path);\n};\n\nconst getFilterDisplayValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n raw: unknown,\n options: {\n enumLabel: (value: string) => string;\n booleanLabel: (value: boolean) => string;\n fallbackBooleanLabels: { yes: string; no: string };\n },\n): ReactNode | null => {\n if (raw == null) {\n return null;\n }\n\n if (Array.isArray(raw)) {\n const normalized = raw\n .map((entry) => {\n if (entry == null) {\n return null;\n }\n if (\n typeof entry !== 'string' &&\n typeof entry !== 'number' &&\n typeof entry !== 'boolean'\n ) {\n return null;\n }\n const value = String(entry).trim();\n if (value === '') {\n return null;\n }\n return value;\n })\n .filter((entry): entry is string => {\n return entry != null;\n });\n\n if (normalized.length === 0) {\n return null;\n }\n return normalized.join(', ');\n }\n\n if (typeof raw === 'boolean') {\n if (filter.kind === 'boolean') {\n return options.booleanLabel(raw);\n }\n if (raw) {\n return options.fallbackBooleanLabels.yes;\n }\n return options.fallbackBooleanLabels.no;\n }\n\n if (typeof raw !== 'string' && typeof raw !== 'number') {\n return null;\n }\n\n const rawString = String(raw).trim();\n if (rawString === '') {\n return null;\n }\n\n if (filter.kind === 'entityId') {\n return <EntityFilterValue entityId={filter.entity} id={rawString} />;\n }\n\n if (filter.kind === 'enum') {\n return options.enumLabel(rawString);\n }\n\n return rawString;\n};\n\ntype Props<\n RowView,\n Where extends Record<string, unknown>,\n Sort extends string,\n> = {\n config: BackofficeResolvedListFacetConfig<Where, Sort>;\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n header?: {\n title?: string;\n subtitle?: string;\n };\n headerActions?: ReactNode;\n rows: readonly RowView[];\n getRowId: GetRowId<RowView>;\n columns: readonly DataTableColumn<RowView>[];\n gridTemplateColumns?: string;\n hasNextPage: boolean;\n isLoadingMore: boolean;\n onLoadMore: () => void;\n onRefresh?: () => void;\n totalCount?: number | null;\n emptyState?: JSX.Element;\n isLoadingInitial?: boolean;\n virtualize?: boolean;\n variant?: 'page' | 'embedded';\n showFilters?: boolean;\n};\n\nexport const BackofficeEntityListScaffold = <\n RowView,\n Where extends Record<string, unknown>,\n Sort extends string,\n>(\n props: Props<RowView, Where, Sort>,\n): JSX.Element | null => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const {\n config,\n state,\n pushState,\n rows,\n getRowId,\n columns,\n gridTemplateColumns,\n hasNextPage,\n isLoadingMore,\n onLoadMore,\n onRefresh,\n totalCount,\n emptyState,\n header,\n headerActions,\n isLoadingInitial = false,\n virtualize = true,\n variant = 'page',\n showFilters = true,\n } = props;\n const listConfig = config.list;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const listDefaults = config.listDefaults ??\n listConfig.defaultState ?? { where: null, sort: null };\n\n const columnsWithPrimary = useMemo(() => {\n const hasPrimary = columns.some((col) => {\n return col.isPrimary === true;\n });\n if (hasPrimary || columns.length === 0) {\n return columns;\n }\n return columns.map((col, index) => {\n const { header } = col;\n if (index === 0) {\n return { ...col, isPrimary: true, header };\n }\n return { ...col, header };\n });\n }, [columns]);\n\n const chips = useMemo<readonly FilterChip[]>(() => {\n const out: FilterChip[] = [];\n for (const filter of listConfig.filters) {\n const raw = getFilterValue(filter, state.where);\n const displayValue = getFilterDisplayValue(filter, raw, {\n enumLabel: (value) => {\n if (filter.kind !== 'enum') {\n return value;\n }\n const match = filter.options.find((option) => {\n return option.value === value;\n });\n if (match != null) {\n return resolveLabel(match.label, tApp);\n }\n return value;\n },\n booleanLabel: (value) => {\n if (filter.kind === 'boolean') {\n if (value && filter.trueLabel != null) {\n return resolveLabel(filter.trueLabel, tApp);\n }\n if (!value && filter.falseLabel != null) {\n return resolveLabel(filter.falseLabel, tApp);\n }\n }\n if (value) {\n return t('filters.boolean.yes');\n }\n return t('filters.boolean.no');\n },\n fallbackBooleanLabels: {\n yes: t('filters.boolean.yes'),\n no: t('filters.boolean.no'),\n },\n });\n\n if (displayValue != null) {\n let idValue = String(raw);\n if (Array.isArray(raw)) {\n idValue = raw.join(',');\n }\n const label = (\n <span>\n {resolveLabel(filter.label, tApp)}: {displayValue}\n </span>\n );\n out.push({\n id: `${filter.id}:${idValue}`,\n label,\n onRemove: () => {\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n },\n });\n }\n }\n return out;\n }, [listConfig.filters, pushState, state, t, tApp]);\n\n const handleClearAll = useCallback(() => {\n pushState({\n ...listDefaults,\n });\n }, [listDefaults, pushState]);\n const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false);\n const [filterSearch, setFilterSearch] = useState('');\n\n const [pickerDialog, setPickerDialog] = useState<{\n entity: string;\n whereKey: keyof Where;\n label: string;\n path?: readonly string[];\n scope?: BackofficePickerScope;\n } | null>(null);\n\n const renderFilterControl = useCallback(\n (filter: BackofficeFilterSpec<Where>): JSX.Element => {\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n const candidate = getFilterValue(filter, state.where);\n let value = '';\n if (typeof candidate === 'string') {\n value = candidate;\n }\n\n const filterLabelText = resolveLabel(filter.label, tApp);\n\n if (filter.kind === 'text') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <GlobalSearchInput\n value={value}\n onChange={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n className={styles.filterInput}\n />\n );\n }\n\n if (filter.kind === 'enum') {\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n ...filter.options.map((option) => {\n return {\n id: option.value,\n value: option.value,\n label: resolveLabel(option.label, tApp),\n };\n }),\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={value}\n onChange={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n if (filter.kind === 'boolean') {\n let current: boolean | null = null;\n if (typeof candidate === 'boolean') {\n current = candidate;\n }\n\n let selectValue = '';\n if (current === true) {\n selectValue = 'true';\n }\n if (current === false) {\n selectValue = 'false';\n }\n\n const trueLabel =\n filter.trueLabel != null\n ? resolveLabel(filter.trueLabel, tApp)\n : t('filters.boolean.yes');\n const falseLabel =\n filter.falseLabel != null\n ? resolveLabel(filter.falseLabel, tApp)\n : t('filters.boolean.no');\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n {\n id: 'true',\n value: 'true',\n label: trueLabel,\n },\n {\n id: 'false',\n value: 'false',\n label: falseLabel,\n },\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={selectValue}\n onChange={(next) => {\n let parsed: boolean | null = null;\n if (next === 'true') {\n parsed = true;\n }\n if (next === 'false') {\n parsed = false;\n }\n const nextWhere = setWhereValue(\n state.where,\n key,\n parsed,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n const pickerScope = (() => {\n if (filter.pickerScope == null) {\n return undefined;\n }\n if (typeof filter.pickerScope === 'function') {\n return filter.pickerScope(state.where);\n }\n return filter.pickerScope;\n })();\n let currentId: string | null = null;\n if (typeof candidate === 'string') {\n currentId = candidate;\n }\n\n const renderField = (displayValue: string | null = null) => {\n const normalizedDisplayValue = displayValue?.trim() ?? '';\n return (\n <EntityIdFilterField\n label={filterLabelText}\n value={currentId}\n displayValue={normalizedDisplayValue}\n onPick={() => {\n setPickerDialog({\n entity: filter.entity,\n whereKey: key,\n label: filterLabelText,\n path: filter.path,\n scope: pickerScope,\n });\n }}\n onClear={() => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n };\n\n if (currentId == null || currentId.trim() === '') {\n return renderField();\n }\n\n return (\n <EntityFilterValueText entityId={filter.entity} id={currentId}>\n {(label) => {\n return renderField(label);\n }}\n </EntityFilterValueText>\n );\n },\n [pushState, state, t, tApp],\n );\n\n const hasPlacementConfig = useMemo(() => {\n return listConfig.filters.some((filter) => {\n return filter.placement != null;\n });\n }, [listConfig.filters]);\n\n const quickFilters = useMemo(() => {\n if (listConfig.filters.length === 0) {\n return [];\n }\n if (hasPlacementConfig) {\n return listConfig.filters.filter((filter) => {\n return filter.placement === 'quick' || filter.placement === 'both';\n });\n }\n return listConfig.filters.slice(0, 3);\n }, [listConfig.filters, hasPlacementConfig]);\n\n const drawerFilters = useMemo(() => {\n return listConfig.filters.filter((filter) => {\n if (filter.placement == null) {\n return true;\n }\n return filter.placement === 'drawer' || filter.placement === 'both';\n });\n }, [listConfig.filters]);\n\n const searchFilter = useMemo(() => {\n return quickFilters.find((filter) => {\n return filter.kind === 'text';\n });\n }, [quickFilters]);\n\n const quickFiltersNode = useMemo(() => {\n const visibleQuickFilters = quickFilters.filter((filter) => {\n return filter !== searchFilter;\n });\n\n if (visibleQuickFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={styles.controlsRow}>\n {visibleQuickFilters.map((filter) => {\n return <span key={filter.id}>{renderFilterControl(filter)}</span>;\n })}\n </div>\n );\n }, [quickFilters, renderFilterControl, searchFilter]);\n\n const searchNode = useMemo(() => {\n if (searchFilter == null) {\n return null;\n }\n return renderFilterControl(searchFilter);\n }, [renderFilterControl, searchFilter]);\n\n const sortNode = useMemo(() => {\n if (listConfig.sorts.length === 0) {\n return null;\n }\n const firstSort = listConfig.sorts[0];\n if (firstSort == null) {\n return null;\n }\n const options = listConfig.sorts.map((s) => {\n return { id: s.id, value: s.id, label: resolveLabel(s.label, tApp) };\n });\n return (\n <SimpleSelect\n options={options}\n value={state.sort ?? firstSort.id}\n onChange={(next) => {\n pushState({\n ...state,\n sort: next as Sort,\n });\n }}\n />\n );\n }, [listConfig.sorts, pushState, state, tApp]);\n\n const chipsNode = useMemo(() => {\n return <FilterChipRow chips={chips} onClearAll={handleClearAll} />;\n }, [chips, handleClearAll]);\n\n const drawerSections = useMemo(() => {\n if (drawerFilters.length === 0) {\n return [];\n }\n\n const normalizedQuery = filterSearch.trim().toLowerCase();\n const items: { id: string; node: JSX.Element }[] = [];\n\n for (const filter of drawerFilters) {\n const resolvedLabel = resolveLabel(filter.label, tApp);\n const matchesQuery =\n normalizedQuery === '' ||\n resolvedLabel.toLowerCase().includes(normalizedQuery);\n\n if (matchesQuery) {\n items.push({\n id: filter.id,\n node: (\n <BackofficeFilterField label={resolvedLabel}>\n {renderFilterControl(filter)}\n </BackofficeFilterField>\n ),\n });\n }\n }\n\n if (items.length === 0) {\n return [];\n }\n\n return [\n {\n id: 'backoffice.filters.sections.default',\n title: t('filters.sections.default'),\n items,\n },\n ];\n }, [drawerFilters, filterSearch, renderFilterControl, t, tApp]);\n\n const allFiltersNode = useMemo(() => {\n if (drawerFilters.length === 0) {\n return null;\n }\n const activeCount = chips.length;\n let label = t('filters.allFilters');\n if (activeCount > 0) {\n label = t('filters.allFiltersWithCount', {\n count: activeCount,\n });\n }\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={() => {\n setIsFilterDrawerOpen(true);\n }}\n >\n {label}\n </Button>\n );\n }, [chips.length, drawerFilters.length, t]);\n\n const filterDrawerNode = (\n <BackofficeFilterDrawer\n isOpen={isFilterDrawerOpen}\n onClose={() => {\n setIsFilterDrawerOpen(false);\n setFilterSearch('');\n }}\n sections={drawerSections}\n searchValue={filterSearch}\n onSearchChange={(next) => {\n setFilterSearch(next);\n }}\n onReset={handleClearAll}\n />\n );\n\n const resolvedEmptyState = useMemo((): JSX.Element => {\n if (emptyState != null) {\n return emptyState;\n }\n\n if (isLoadingInitial) {\n return <BackofficeTableSkeleton />;\n }\n\n if (chips.length > 0) {\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmptyFiltered.description')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={handleClearAll}\n >\n {t('emptyState.listEmptyFiltered.actions.reset')}\n </Button>\n }\n />\n );\n }\n\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmpty.description')}\n />\n );\n }, [chips.length, emptyState, handleClearAll, isLoadingInitial, t]);\n\n const tableFooterMeta = useMemo(() => {\n if (typeof totalCount !== 'number') {\n return null;\n }\n return (\n <span>\n {t('list.showing', {\n shown: rows.length,\n total: totalCount,\n })}\n </span>\n );\n }, [rows.length, t, totalCount]);\n\n const headerTitle = header?.title ?? resolveLabel(listConfig.title, tApp);\n const headerSubtitle = header?.subtitle;\n\n const virtualizationConfig = useMemo(() => {\n if (!virtualize) {\n return { enabled: false, rowHeightPx: 0, overscan: 0 };\n }\n\n return { enabled: true, rowHeightPx: 52, overscan: 10 };\n }, [virtualize]);\n\n const tableInnerNode = (\n <BackofficeVirtualizedConnectionTable\n columns={columnsWithPrimary}\n rows={rows}\n getRowId={getRowId}\n emptyState={resolvedEmptyState}\n className={denseTableClass}\n gridTemplateColumns={gridTemplateColumns}\n virtualization={virtualizationConfig}\n infiniteScroll={{\n enabled: true,\n thresholdPx: 800,\n autoLoad: true,\n }}\n hasNextPage={hasNextPage}\n isLoadingMore={isLoadingMore}\n onLoadMore={onLoadMore}\n />\n );\n\n const tableNodeWithErrorBoundary = (\n <BackofficeErrorBoundary\n fallback={(args: { error: unknown; reset: () => void }) => {\n const { reset } = args;\n\n const retry = (): void => {\n reset();\n if (onRefresh != null) {\n onRefresh();\n }\n };\n\n return (\n <InlineBanner\n tone=\"danger\"\n title={t('list.errors.title')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={retry}\n >\n {t('list.actions.retry')}\n </Button>\n }\n >\n {t('list.errors.tableFailed')}\n </InlineBanner>\n );\n }}\n >\n {tableInnerNode}\n </BackofficeErrorBoundary>\n );\n\n const filtersBarNode = showFilters ? (\n <>\n <BackofficeTableToolbar\n searchSlot={searchNode}\n filtersSlot={\n <>\n {quickFiltersNode}\n {allFiltersNode}\n </>\n }\n sortSlot={sortNode}\n refreshSlot={\n <Button\n type=\"button\"\n variant=\"text\"\n size=\"small\"\n disabled={onRefresh == null}\n onClick={() => {\n if (onRefresh != null) {\n onRefresh();\n }\n }}\n >\n {t('list.actions.refresh')}\n </Button>\n }\n chipsSlot={chipsNode}\n />\n {filterDrawerNode}\n </>\n ) : null;\n\n const tableNode = (\n <div>\n {tableNodeWithErrorBoundary}\n <EntityIdPickerDialog\n isOpen={pickerDialog != null}\n entity={pickerDialog?.entity ?? config.id}\n title={pickerDialog?.label ?? t('picker.title')}\n scope={pickerDialog?.scope}\n onClose={() => {\n setPickerDialog(null);\n }}\n onSelectId={(id) => {\n if (pickerDialog == null) {\n return;\n }\n const nextWhere = setWhereValue(\n state.where,\n pickerDialog.whereKey,\n id,\n pickerDialog.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n </div>\n );\n\n const tableFooterNode = (\n <BackofficeLoadMore\n hasNextPage={hasNextPage}\n isLoading={isLoadingMore}\n meta={tableFooterMeta}\n loadMoreLabel={t('list.loadMore.more')}\n endLabel={t('list.loadMore.end')}\n loadingLabel={t('list.loadMore.loading')}\n />\n );\n\n if (variant === 'embedded') {\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <div className={styles.embeddedContainer}>\n <div className={styles.embeddedHeader}>{headerTitle}</div>\n {filtersBarNode}\n {tableNode}\n {tableFooterNode}\n </div>\n </BackofficeListFilterProvider>\n );\n }\n\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <ListPageTemplate\n headerNode={\n <BackofficePageHeader\n title={headerTitle}\n subtitle={headerSubtitle}\n actions={headerActions}\n />\n }\n toolbarNode={filtersBarNode}\n tableNode={tableNode}\n tableFooterNode={tableFooterNode}\n />\n </BackofficeListFilterProvider>\n );\n};\n\nexport default BackofficeEntityListScaffold;\n","import { Suspense, lazy, type JSX } from 'react';\n\nimport type { BackofficeEntityActionFormDialogProps } from './BackofficeEntityActionFormDialog.js';\n\nconst BackofficeEntityActionFormDialog = lazy(async () => {\n const module = await import('./BackofficeEntityActionFormDialog.js');\n return { default: module.BackofficeEntityActionFormDialog };\n});\n\nexport const LazyBackofficeEntityActionFormDialog = <Node,>(\n props: BackofficeEntityActionFormDialogProps<Node>,\n): JSX.Element => {\n const Dialog = BackofficeEntityActionFormDialog as <TNode>(\n dialogProps: BackofficeEntityActionFormDialogProps<TNode>,\n ) => JSX.Element;\n\n return (\n <Suspense fallback={null}>\n <Dialog {...props} />\n </Suspense>\n );\n};\n\nexport default LazyBackofficeEntityActionFormDialog;\n"],"mappings":";;;;;;;;;;AAYA,SAAgB,EAAsB,EACpC,YACA,kBACA,aACA,YACqB;AACrB,QAAO,QAAkB;AACnB,GAAC,KAAW,KAIhB,QAAsB;AACpB,KAAS,EAAM;IACf;IACD;EAAC;EAAO;EAAS;EAAe;EAAS,CAAC;;;;ACA/C,SAAgB,GAId,EACA,YACA,cACA,aACA,gBACA,qBAC4D;CAC5D,IAAM,IAAoB,EACxB,EAAuB;EACrB,OAAO,EAAS;EAChB,MAAM,EAAS;EACf,OAAO,EAAS;EACjB,CAAC,CACH,EAEK,IAAmB,GACtB,MACK,KAAkB,OAGf,IAFE,EAAe,EAAM,EAIhC,CAAC,EAAe,CACjB;AAsBD,QApBA,QAAgB;EACd,IAAM,IAAM,EAAuB;GACjC,OAAO,EAAU;GACjB,MAAM,EAAU;GAChB,OAAO,EAAU;GAClB,CAAC;AACE,IAAkB,YAAY,MAGlC,EAAkB,UAAU,GAG5B,EADsB,EAAiB;GAAE,GAAG;GAAW,QAAQ;GAAM,CAAC,EAC/C,EAAE,gBAAa,CAAC;IACtC;EAAC;EAAa;EAAS;EAAkB;EAAU,CAAC,EAOhD,EAAE,WALS,QAAkB;AAElC,IADsB,EAAiB;GAAE,GAAG;GAAW,QAAQ;GAAM,CAAC,EAC/C,EAAE,gBAAa,CAAC;IACtC;EAAC;EAAa;EAAS;EAAkB;EAAU,CAAC,EAEnC;;;;0JEpBhB,KAAgB,GAAkB,MAC/B,EAAM,EAAK,EAGd,KACJ,GACA,MAEI,EAAO,eAAe,QAAQ,KAAS,OAClC,EAAO,YAAY,EAAM,GAI3B,EAAe,GADT,EAAO,YAAY,EAAO,IACL,EAAO,KAAK,EAG1C,MACJ,GACA,GACA,MAKqB;AACrB,KAAI,KAAO,KACT,QAAO;AAGT,KAAI,MAAM,QAAQ,EAAI,EAAE;EACtB,IAAM,IAAa,EAChB,KAAK,MAAU;AAId,OAHI,KAAS,QAIX,OAAO,KAAU,YACjB,OAAO,KAAU,YACjB,OAAO,KAAU,UAEjB,QAAO;GAET,IAAM,IAAQ,OAAO,EAAM,CAAC,MAAM;AAIlC,UAHI,MAAU,KACL,OAEF;IACP,CACD,QAAQ,MACA,KAAS,KAChB;AAKJ,SAHI,EAAW,WAAW,IACjB,OAEF,EAAW,KAAK,KAAK;;AAG9B,KAAI,OAAO,KAAQ,UAOjB,QANI,EAAO,SAAS,YACX,EAAQ,aAAa,EAAI,GAE9B,IACK,EAAQ,sBAAsB,MAEhC,EAAQ,sBAAsB;AAGvC,KAAI,OAAO,KAAQ,YAAY,OAAO,KAAQ,SAC5C,QAAO;CAGT,IAAM,IAAY,OAAO,EAAI,CAAC,MAAM;AAapC,QAZI,MAAc,KACT,OAGL,EAAO,SAAS,aACX,kBAAC,GAAD;EAAmB,UAAU,EAAO;EAAQ,IAAI;EAAa,CAAA,GAGlE,EAAO,SAAS,SACX,EAAQ,UAAU,EAAU,GAG9B;GAgCI,KAKX,MACuB;CACvB,IAAM,EAAE,GAAG,MAAS,IAAgB,EAC9B,EAAE,SAAM,GAA+B,EACvC,EACJ,WACA,UACA,cACA,SACA,aACA,YACA,yBACA,gBACA,kBACA,eACA,cACA,eACA,eACA,WACA,mBACA,sBAAmB,IACnB,gBAAa,IACb,cAAU,QACV,kBAAc,OACZ,GACE,IAAa,EAAO,MAEpB,IAAe,EAAO,gBAC1B,EAAW,gBAAgB;EAAE,OAAO;EAAM,MAAM;EAAM,EAElD,KAAqB,QACN,EAAQ,MAAM,MACxB,EAAI,cAAc,GACzB,IACgB,EAAQ,WAAW,IAC5B,IAEF,EAAQ,KAAK,GAAK,MAAU;EACjC,IAAM,EAAE,cAAW;AAInB,SAHI,MAAU,IACL;GAAE,GAAG;GAAK,WAAW;GAAM;GAAQ,GAErC;GAAE,GAAG;GAAK;GAAQ;GACzB,EACD,CAAC,EAAQ,CAAC,EAEP,IAAQ,QAAqC;EACjD,IAAM,IAAoB,EAAE;AAC5B,OAAK,IAAM,KAAU,EAAW,SAAS;GACvC,IAAM,IAAM,EAAe,GAAQ,EAAM,MAAM,EACzC,IAAe,GAAsB,GAAQ,GAAK;IACtD,YAAY,MAAU;AACpB,SAAI,EAAO,SAAS,OAClB,QAAO;KAET,IAAM,IAAQ,EAAO,QAAQ,MAAM,MAC1B,EAAO,UAAU,EACxB;AAIF,YAHI,KAAS,OAGN,IAFE,EAAa,EAAM,OAAO,EAAK;;IAI1C,eAAe,MAAU;AACvB,SAAI,EAAO,SAAS,WAAW;AAC7B,UAAI,KAAS,EAAO,aAAa,KAC/B,QAAO,EAAa,EAAO,WAAW,EAAK;AAE7C,UAAI,CAAC,KAAS,EAAO,cAAc,KACjC,QAAO,EAAa,EAAO,YAAY,EAAK;;AAMhD,YAFS,EADL,IACO,wBAEF,qBAFwB;;IAInC,uBAAuB;KACrB,KAAK,EAAE,sBAAsB;KAC7B,IAAI,EAAE,qBAAqB;KAC5B;IACF,CAAC;AAEF,OAAI,KAAgB,MAAM;IACxB,IAAI,IAAU,OAAO,EAAI;AACzB,IAAI,MAAM,QAAQ,EAAI,KACpB,IAAU,EAAI,KAAK,IAAI;IAEzB,IAAM,IACJ,kBAAC,QAAD,EAAA,UAAA;KACG,EAAa,EAAO,OAAO,EAAK;KAAC;KAAG;KAChC,EAAA,CAAA;AAET,MAAI,KAAK;KACP,IAAI,GAAG,EAAO,GAAG,GAAG;KACpB;KACA,gBAAgB;MACd,IAAM,IAAO,EAAO,YAAY,EAAO,IACjC,IAAY,EAChB,EAAM,OACN,GACA,MACA,EAAO,KACR;AACD,QAAU;OAAE,GAAG;OAAO,OAAO;OAAW,CAAC;;KAE5C,CAAC;;;AAGN,SAAO;IACN;EAAC,EAAW;EAAS;EAAW;EAAO;EAAG;EAAK,CAAC,EAE7C,IAAiB,QAAkB;AACvC,IAAU,EACR,GAAG,GACJ,CAAC;IACD,CAAC,GAAc,EAAU,CAAC,EACvB,CAAC,IAAoB,KAAyB,EAAS,GAAM,EAC7D,CAAC,GAAc,KAAmB,EAAS,GAAG,EAE9C,CAAC,GAAc,KAAmB,EAM9B,KAAK,EAET,IAAsB,GACzB,MAAqD;EACpD,IAAM,IAAO,EAAO,YAAY,EAAO,IACjC,IAAY,EAAe,GAAQ,EAAM,MAAM,EACjD,IAAQ;AACZ,EAAI,OAAO,KAAc,aACvB,IAAQ;EAGV,IAAM,IAAkB,EAAa,EAAO,OAAO,EAAK;AAExD,MAAI,EAAO,SAAS,QAAQ;GAK1B,IAAI,IAAc,EAAE,+BAA+B,EACjD,OAJA,EAAO,oBAAoB,OAEvB,IADA,EAAa,EAAO,kBAAkB,EAAK,EAIhD,CAAC;AAIF,UAHI,EAAO,mBAAmB,SAC5B,IAAc,EAAa,EAAO,iBAAiB,EAAK,GAGxD,kBAAC,IAAD;IACS;IACP,WAAW,MAAS;KAClB,IAAM,IAAY,EAChB,EAAM,OACN,GACA,GACA,EAAO,KACR;AACD,OAAU;MAAE,GAAG;MAAO,OAAO;MAAW,CAAC;;IAE9B;IACb,WAAW;IACX,CAAA;;AAIN,MAAI,EAAO,SAAS,OAkBlB,QACE,kBAAC,GAAD;GACW,SAnBG,CACd;IACE,IAAI;IACJ,OAAO;IACP,OAAO,EAAE,eAAe,EACtB,OAAO,GACR,CAAC;IACH,EACD,GAAG,EAAO,QAAQ,KAAK,OACd;IACL,IAAI,EAAO;IACX,OAAO,EAAO;IACd,OAAO,EAAa,EAAO,OAAO,EAAK;IACxC,EACD,CACH;GAKU;GACP,WAAW,MAAS;IAClB,IAAM,IAAY,EAChB,EAAM,OACN,GACA,GACA,EAAO,KACR;AACD,MAAU;KAAE,GAAG;KAAO,OAAO;KAAW,CAAC;;GAE3C,CAAA;AAIN,MAAI,EAAO,SAAS,WAAW;GAC7B,IAAI,IAA0B;AAC9B,GAAI,OAAO,KAAc,cACvB,IAAU;GAGZ,IAAI,IAAc;AAIlB,GAHI,MAAY,OACd,IAAc,SAEZ,MAAY,OACd,IAAc;GAGhB,IAAM,IACJ,EAAO,aAAa,OAEhB,EAAE,sBAAsB,GADxB,EAAa,EAAO,WAAW,EAAK,EAEpC,IACJ,EAAO,cAAc,OAEjB,EAAE,qBAAqB,GADvB,EAAa,EAAO,YAAY,EAAK;AAsB3C,UACE,kBAAC,GAAD;IACW,SAtBG;KACd;MACE,IAAI;MACJ,OAAO;MACP,OAAO,EAAE,eAAe,EACtB,OAAO,GACR,CAAC;MACH;KACD;MACE,IAAI;MACJ,OAAO;MACP,OAAO;MACR;KACD;MACE,IAAI;MACJ,OAAO;MACP,OAAO;MACR;KACF;IAKG,OAAO;IACP,WAAW,MAAS;KAClB,IAAI,IAAyB;AAI7B,KAHI,MAAS,WACX,IAAS,KAEP,MAAS,YACX,IAAS;KAEX,IAAM,IAAY,EAChB,EAAM,OACN,GACA,GACA,EAAO,KACR;AACD,OAAU;MAAE,GAAG;MAAO,OAAO;MAAW,CAAC;;IAE3C,CAAA;;EAIN,IAAM,WAAqB;AACrB,SAAO,eAAe,KAM1B,QAHI,OAAO,EAAO,eAAgB,aACzB,EAAO,YAAY,EAAM,MAAM,GAEjC,EAAO;MACZ,EACA,IAA2B;AAC/B,EAAI,OAAO,KAAc,aACvB,IAAY;EAGd,IAAM,KAAe,IAA8B,SAAS;GAC1D,IAAM,IAAyB,GAAc,MAAM,IAAI;AACvD,UACE,kBAAC,GAAD;IACE,OAAO;IACP,OAAO;IACP,cAAc;IACd,cAAc;AACZ,OAAgB;MACd,QAAQ,EAAO;MACf,UAAU;MACV,OAAO;MACP,MAAM,EAAO;MACb,OAAO;MACR,CAAC;;IAEJ,eAAe;KACb,IAAM,IAAY,EAChB,EAAM,OACN,GACA,MACA,EAAO,KACR;AACD,OAAU;MAAE,GAAG;MAAO,OAAO;MAAW,CAAC;;IAE3C,CAAA;;AAQN,SAJI,KAAa,QAAQ,EAAU,MAAM,KAAK,KACrC,GAAa,GAIpB,kBAAC,GAAD;GAAuB,UAAU,EAAO;GAAQ,IAAI;cAChD,MACO,EAAY,EAAM;GAEL,CAAA;IAG5B;EAAC;EAAW;EAAO;EAAG;EAAK,CAC5B,EAEK,IAAqB,QAClB,EAAW,QAAQ,MAAM,MACvB,EAAO,aAAa,KAC3B,EACD,CAAC,EAAW,QAAQ,CAAC,EAElB,IAAe,QACf,EAAW,QAAQ,WAAW,IACzB,EAAE,GAEP,IACK,EAAW,QAAQ,QAAQ,MACzB,EAAO,cAAc,WAAW,EAAO,cAAc,OAC5D,GAEG,EAAW,QAAQ,MAAM,GAAG,EAAE,EACpC,CAAC,EAAW,SAAS,EAAmB,CAAC,EAEtC,IAAgB,QACb,EAAW,QAAQ,QAAQ,MAC5B,EAAO,aAAa,OACf,KAEF,EAAO,cAAc,YAAY,EAAO,cAAc,OAC7D,EACD,CAAC,EAAW,QAAQ,CAAC,EAElB,IAAe,QACZ,EAAa,MAAM,MACjB,EAAO,SAAS,OACvB,EACD,CAAC,EAAa,CAAC,EAEZ,KAAmB,QAAc;EACrC,IAAM,IAAsB,EAAa,QAAQ,MACxC,MAAW,EAClB;AAMF,SAJI,EAAoB,WAAW,IAC1B,OAIP,kBAAC,OAAD;GAAK,WAAW;aACb,EAAoB,KAAK,MACjB,kBAAC,QAAD,EAAA,UAAuB,EAAoB,EAAO,EAAQ,EAA/C,EAAO,GAAwC,CACjE;GACE,CAAA;IAEP;EAAC;EAAc;EAAqB;EAAa,CAAC,EAE/C,KAAa,QACb,KAAgB,OACX,OAEF,EAAoB,EAAa,EACvC,CAAC,GAAqB,EAAa,CAAC,EAEjC,KAAW,QAAc;AAC7B,MAAI,EAAW,MAAM,WAAW,EAC9B,QAAO;EAET,IAAM,IAAY,EAAW,MAAM;AAOnC,SANI,KAAa,OACR,OAMP,kBAAC,GAAD;GACW,SALG,EAAW,MAAM,KAAK,OAC7B;IAAE,IAAI,EAAE;IAAI,OAAO,EAAE;IAAI,OAAO,EAAa,EAAE,OAAO,EAAK;IAAE,EACpE;GAIE,OAAO,EAAM,QAAQ,EAAU;GAC/B,WAAW,MAAS;AAClB,MAAU;KACR,GAAG;KACH,MAAM;KACP,CAAC;;GAEJ,CAAA;IAEH;EAAC,EAAW;EAAO;EAAW;EAAO;EAAK,CAAC,EAExC,KAAY,QACT,kBAAC,IAAD;EAAsB;EAAO,YAAY;EAAkB,CAAA,EACjE,CAAC,GAAO,EAAe,CAAC,EAErB,KAAiB,QAAc;AACnC,MAAI,EAAc,WAAW,EAC3B,QAAO,EAAE;EAGX,IAAM,IAAkB,EAAa,MAAM,CAAC,aAAa,EACnD,IAA6C,EAAE;AAErD,OAAK,IAAM,KAAU,GAAe;GAClC,IAAM,IAAgB,EAAa,EAAO,OAAO,EAAK;AAKtD,IAHE,MAAoB,MACpB,EAAc,aAAa,CAAC,SAAS,EAAgB,KAGrD,EAAM,KAAK;IACT,IAAI,EAAO;IACX,MACE,kBAAC,IAAD;KAAuB,OAAO;eAC3B,EAAoB,EAAO;KACN,CAAA;IAE3B,CAAC;;AAQN,SAJI,EAAM,WAAW,IACZ,EAAE,GAGJ,CACL;GACE,IAAI;GACJ,OAAO,EAAE,2BAA2B;GACpC;GACD,CACF;IACA;EAAC;EAAe;EAAc;EAAqB;EAAG;EAAK,CAAC,EAEzD,KAAiB,QAAc;AACnC,MAAI,EAAc,WAAW,EAC3B,QAAO;EAET,IAAM,IAAc,EAAM,QACtB,IAAQ,EAAE,qBAAqB;AAMnC,SALI,IAAc,MAChB,IAAQ,EAAE,+BAA+B,EACvC,OAAO,GACR,CAAC,GAGF,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,MAAK;GACL,eAAe;AACb,MAAsB,GAAK;;aAG5B;GACM,CAAA;IAEV;EAAC,EAAM;EAAQ,EAAc;EAAQ;EAAE,CAAC,EAErC,KACJ,kBAAC,IAAD;EACE,QAAQ;EACR,eAAe;AAEb,GADA,EAAsB,GAAM,EAC5B,EAAgB,GAAG;;EAErB,UAAU;EACV,aAAa;EACb,iBAAiB,MAAS;AACxB,KAAgB,EAAK;;EAEvB,SAAS;EACT,CAAA,EAGE,KAAqB,QACrB,MAIA,IACK,kBAAC,IAAD,EAA2B,CAAA,GAGhC,EAAM,SAAS,IAEf,kBAAC,GAAD;EACE,OAAO,EAAE,6BAA6B;EACtC,aAAa,EAAE,2CAA2C;EAC1D,SACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,MAAK;GACL,SAAS;aAER,EAAE,6CAA6C;GACzC,CAAA;EAEX,CAAA,GAKJ,kBAAC,GAAD;EACE,OAAO,EAAE,6BAA6B;EACtC,aAAa,EAAE,mCAAmC;EAClD,CAAA,GAEH;EAAC,EAAM;EAAQ;EAAY;EAAgB;EAAkB;EAAE,CAAC,EAE7D,KAAkB,QAClB,OAAO,KAAe,WAIxB,kBAAC,QAAD,EAAA,UACG,EAAE,gBAAgB;EACjB,OAAO,EAAK;EACZ,OAAO;EACR,CAAC,EACG,CAAA,GARA,MAUR;EAAC,EAAK;EAAQ;EAAG;EAAW,CAAC,EAE1B,IAAc,GAAQ,SAAS,EAAa,EAAW,OAAO,EAAK,EACnE,KAAiB,GAAQ,UA8BzB,KACJ,kBAAC,GAAD;EACE,WAAW,MAAgD;GACzD,IAAM,EAAE,aAAU;AASlB,UACE,kBAAC,IAAD;IACE,MAAK;IACL,OAAO,EAAE,oBAAoB;IAC7B,SACE,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,MAAK;KACL,eAhBkB;AAExB,MADA,GAAO,EACH,KACS;;eAeN,EAAE,qBAAqB;KACjB,CAAA;cAGV,EAAE,0BAA0B;IAChB,CAAA;;YA/CrB,kBAAC,IAAD;GACE,SAAS;GACH;GACI;GACV,YAAY;GACZ,WAAW;GACU;GACrB,gBAhByB,QACtB,IAIE;IAAE,SAAS;IAAM,aAAa;IAAI,UAAU;IAAI,GAH9C;IAAE,SAAS;IAAO,aAAa;IAAG,UAAU;IAAG,EAIvD,CAAC,EAAW,CAAC;GAWZ,gBAAgB;IACd,SAAS;IACT,aAAa;IACb,UAAU;IACX;GACY;GACE;GACH;GACZ,CAAA;EAoCwB,CAAA,EAGtB,IAAiB,KACrB,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,IAAD;EACE,YAAY;EACZ,aACE,kBAAA,GAAA,EAAA,UAAA,CACG,IACA,GACA,EAAA,CAAA;EAEL,UAAU;EACV,aACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,MAAK;GACL,UAAU,KAAa;GACvB,eAAe;AACb,IAAI,KACS;;aAId,EAAE,uBAAuB;GACnB,CAAA;EAEX,WAAW;EACX,CAAA,EACD,GACA,EAAA,CAAA,GACD,MAEE,IACJ,kBAAC,OAAD,EAAA,UAAA,CACG,IACD,kBAAC,GAAD;EACE,QAAQ,KAAgB;EACxB,QAAQ,GAAc,UAAU,EAAO;EACvC,OAAO,GAAc,SAAS,EAAE,eAAe;EAC/C,OAAO,GAAc;EACrB,eAAe;AACb,KAAgB,KAAK;;EAEvB,aAAa,MAAO;AAClB,OAAI,KAAgB,KAClB;GAEF,IAAM,IAAY,EAChB,EAAM,OACN,EAAa,UACb,GACA,EAAa,KACd;AACD,KAAU;IAAE,GAAG;IAAO,OAAO;IAAW,CAAC;;EAE3C,CAAA,CACE,EAAA,CAAA,EAGF,IACJ,kBAAC,IAAD;EACe;EACb,WAAW;EACX,MAAM;EACN,eAAe,EAAE,qBAAqB;EACtC,UAAU,EAAE,oBAAoB;EAChC,cAAc,EAAE,wBAAwB;EACxC,CAAA;AAoBJ,QAjBI,OAAY,aAEZ,kBAAC,GAAD;EACU;EACD;EACI;YAEX,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,OAAD;KAAK,WAAW;eAAwB;KAAkB,CAAA;IACzD;IACA;IACA;IACG;;EACuB,CAAA,GAKjC,kBAAC,GAAD;EACU;EACD;EACI;YAEX,kBAAC,IAAD;GACE,YACE,kBAAC,IAAD;IACE,OAAO;IACP,UAAU;IACV,SAAS;IACT,CAAA;GAEJ,aAAa;GACF;GACM;GACjB,CAAA;EAC2B,CAAA;GCz3B7B,IAAmC,EAAK,aAErC,EAAE,UADM,MAAM,OAAO,mDACH,kCAAkC,EAC3D,EAEW,KACX,MAOE,kBAAC,GAAD;CAAU,UAAU;WAClB,kBANW,GAMX,EAAQ,GAAI,GAAS,CAAA;CACZ,CAAA"}
1
+ {"version":3,"file":"LazyBackofficeEntityActionFormDialog-BE3wVfU6.js","names":[],"sources":["../../src/hooks/useBackofficeLoadMore.ts","../../src/hooks/useBackofficeListRefetch.ts","../../src/components/backoffice/scaffolds/backofficeEntityListScaffold.css.ts","../../src/components/backoffice/scaffolds/BackofficeEntityListScaffold.tsx","../../src/components/backoffice/actions/LazyBackofficeEntityActionFormDialog.tsx"],"sourcesContent":["import { startTransition, useCallback } from 'react';\n\ntype Params = {\n hasNext: boolean;\n isLoadingNext: boolean;\n loadNext: (count: number) => void;\n count: number;\n};\n\n/**\n * Wraps Relay `loadNext()` with consistent guards and `startTransition()`.\n */\nexport function useBackofficeLoadMore({\n hasNext,\n isLoadingNext,\n loadNext,\n count,\n}: Params): () => void {\n return useCallback(() => {\n if (!hasNext || isLoadingNext) {\n return;\n }\n\n startTransition(() => {\n loadNext(count);\n });\n }, [count, hasNext, isLoadingNext, loadNext]);\n}\n","import { useCallback, useEffect, useRef } from 'react';\nimport type { FetchPolicy } from 'relay-runtime';\n\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficeListVariables } from '@plumile/backoffice-core/types.js';\n\ntype RefetchFn<TVariables> = (\n vars: TVariables,\n opts: { fetchPolicy: FetchPolicy },\n) => void;\n\ntype Params<Where, Sort extends string, Variables> = {\n refetch: RefetchFn<Variables>;\n variables: BackofficeListVariables<Where, Sort>;\n defaults: BackofficeListVariables<Where, Sort>;\n fetchPolicy: FetchPolicy;\n buildVariables?: (input: BackofficeListVariables<Where, Sort>) => Variables;\n};\n\n/**\n * Standardizes refetch behavior for backoffice list components:\n * - Refetches when list URL state changes (where/sort/count), gated by a stable key.\n * - Exposes a manual refresh callback using the same variables.\n *\n * This hook must not call Relay hooks (`useFragment`, `usePaginationFragment`, ...).\n */\nexport function useBackofficeListRefetch<\n Where,\n Sort extends string,\n Variables extends Record<string, unknown>,\n>({\n refetch,\n variables,\n defaults,\n fetchPolicy,\n buildVariables,\n}: Params<Where, Sort, Variables>): { onRefresh: () => void } {\n const lastRefetchKeyRef = useRef<string | null>(\n stableListVariablesKey({\n where: defaults.where,\n sort: defaults.sort,\n count: defaults.count,\n }),\n );\n\n const resolveVariables = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n if (buildVariables != null) {\n return buildVariables(input);\n }\n return input as unknown as Variables;\n },\n [buildVariables],\n );\n\n useEffect(() => {\n const key = stableListVariablesKey({\n where: variables.where,\n sort: variables.sort,\n count: variables.count,\n });\n if (lastRefetchKeyRef.current === key) {\n return;\n }\n lastRefetchKeyRef.current = key;\n\n const nextVariables = resolveVariables({ ...variables, cursor: null });\n refetch(nextVariables, { fetchPolicy });\n }, [fetchPolicy, refetch, resolveVariables, variables]);\n\n const onRefresh = useCallback(() => {\n const nextVariables = resolveVariables({ ...variables, cursor: null });\n refetch(nextVariables, { fetchPolicy });\n }, [fetchPolicy, refetch, resolveVariables, variables]);\n\n return { onRefresh };\n}\n","import { sprinkles } from '@plumile/ui';\n\nexport const controlsRow = sprinkles({\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 2,\n});\n\nexport const filterInput = sprinkles({\n width: 72,\n maxWidth: 'full',\n});\n\nexport const embeddedContainer = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n});\n\nexport const embeddedHeader = sprinkles({\n fontSize: 'base',\n fontWeight: 'semibold',\n color: 'text',\n});\n","/* eslint-disable no-ternary */\nimport {\n type JSX,\n type ReactNode,\n useCallback,\n useMemo,\n useState,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { useTranslation } from 'react-i18next';\nimport {\n BackofficeEmptyState,\n BackofficeFilterDrawer,\n BackofficeFilterField,\n BackofficeLoadMore,\n BackofficePageHeader,\n BackofficeTableSkeleton,\n BackofficeTableToolbar,\n BackofficeVirtualizedConnectionTable,\n Button,\n FilterChipRow,\n GlobalSearchInput,\n InlineBanner,\n ListPageTemplate,\n SimpleSelect,\n type FilterChip,\n type DataTableColumn,\n type GetRowId,\n denseTableClass,\n} from '@plumile/ui';\n\nimport {\n readWhereValue,\n setWhereValue,\n} from '@plumile/backoffice-core/filters/where.js';\nimport type {\n BackofficeFilterSpec,\n BackofficeListState,\n BackofficePickerScope,\n BackofficeResolvedListFacetConfig,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\nimport {\n EntityFilterValue,\n EntityFilterValueText,\n} from '../filters/EntityFilterValue.js';\nimport { EntityIdPickerDialog } from '../pickers/EntityIdPickerDialog.js';\nimport { EntityIdFilterField } from '../filters/EntityIdFilterField.js';\nimport { BackofficeListFilterProvider } from './BackofficeListFilterContext.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './backofficeEntityListScaffold.css.js';\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nconst getFilterValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n where: Where | null,\n): unknown => {\n if (filter.fromGraphQL != null && where != null) {\n return filter.fromGraphQL(where);\n }\n\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n return readWhereValue(where, key, filter.path);\n};\n\nconst getFilterDisplayValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n raw: unknown,\n options: {\n enumLabel: (value: string) => string;\n booleanLabel: (value: boolean) => string;\n fallbackBooleanLabels: { yes: string; no: string };\n },\n): ReactNode | null => {\n if (raw == null) {\n return null;\n }\n\n if (Array.isArray(raw)) {\n const normalized = raw\n .map((entry) => {\n if (entry == null) {\n return null;\n }\n if (\n typeof entry !== 'string' &&\n typeof entry !== 'number' &&\n typeof entry !== 'boolean'\n ) {\n return null;\n }\n const value = String(entry).trim();\n if (value === '') {\n return null;\n }\n return value;\n })\n .filter((entry): entry is string => {\n return entry != null;\n });\n\n if (normalized.length === 0) {\n return null;\n }\n return normalized.join(', ');\n }\n\n if (typeof raw === 'boolean') {\n if (filter.kind === 'boolean') {\n return options.booleanLabel(raw);\n }\n if (raw) {\n return options.fallbackBooleanLabels.yes;\n }\n return options.fallbackBooleanLabels.no;\n }\n\n if (typeof raw !== 'string' && typeof raw !== 'number') {\n return null;\n }\n\n const rawString = String(raw).trim();\n if (rawString === '') {\n return null;\n }\n\n if (filter.kind === 'entityId') {\n return <EntityFilterValue entityId={filter.entity} id={rawString} />;\n }\n\n if (filter.kind === 'enum') {\n return options.enumLabel(rawString);\n }\n\n return rawString;\n};\n\ntype Props<\n RowView,\n Where extends Record<string, unknown>,\n Sort extends string,\n> = {\n config: BackofficeResolvedListFacetConfig<Where, Sort>;\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n header?: {\n title?: string;\n subtitle?: string;\n };\n headerActions?: ReactNode;\n rows: readonly RowView[];\n getRowId: GetRowId<RowView>;\n columns: readonly DataTableColumn<RowView>[];\n gridTemplateColumns?: string;\n hasNextPage: boolean;\n isLoadingMore: boolean;\n onLoadMore: () => void;\n onRefresh?: () => void;\n totalCount?: number | null;\n emptyState?: JSX.Element;\n isLoadingInitial?: boolean;\n virtualize?: boolean;\n variant?: 'page' | 'embedded';\n showFilters?: boolean;\n};\n\nexport const BackofficeEntityListScaffold = <\n RowView,\n Where extends Record<string, unknown>,\n Sort extends string,\n>(\n props: Props<RowView, Where, Sort>,\n): JSX.Element | null => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const {\n config,\n state,\n pushState,\n rows,\n getRowId,\n columns,\n gridTemplateColumns,\n hasNextPage,\n isLoadingMore,\n onLoadMore,\n onRefresh,\n totalCount,\n emptyState,\n header,\n headerActions,\n isLoadingInitial = false,\n virtualize = true,\n variant = 'page',\n showFilters = true,\n } = props;\n const listConfig = config.list;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const listDefaults = config.listDefaults ??\n listConfig.defaultState ?? { where: null, sort: null };\n\n const columnsWithPrimary = useMemo(() => {\n const hasPrimary = columns.some((col) => {\n return col.isPrimary === true;\n });\n if (hasPrimary || columns.length === 0) {\n return columns;\n }\n return columns.map((col, index) => {\n const { header } = col;\n if (index === 0) {\n return { ...col, isPrimary: true, header };\n }\n return { ...col, header };\n });\n }, [columns]);\n\n const chips = useMemo<readonly FilterChip[]>(() => {\n const out: FilterChip[] = [];\n for (const filter of listConfig.filters) {\n const raw = getFilterValue(filter, state.where);\n const displayValue = getFilterDisplayValue(filter, raw, {\n enumLabel: (value) => {\n if (filter.kind !== 'enum') {\n return value;\n }\n const match = filter.options.find((option) => {\n return option.value === value;\n });\n if (match != null) {\n return resolveLabel(match.label, tApp);\n }\n return value;\n },\n booleanLabel: (value) => {\n if (filter.kind === 'boolean') {\n if (value && filter.trueLabel != null) {\n return resolveLabel(filter.trueLabel, tApp);\n }\n if (!value && filter.falseLabel != null) {\n return resolveLabel(filter.falseLabel, tApp);\n }\n }\n if (value) {\n return t('filters.boolean.yes');\n }\n return t('filters.boolean.no');\n },\n fallbackBooleanLabels: {\n yes: t('filters.boolean.yes'),\n no: t('filters.boolean.no'),\n },\n });\n\n if (displayValue != null) {\n let idValue = String(raw);\n if (Array.isArray(raw)) {\n idValue = raw.join(',');\n }\n const label = (\n <span>\n {resolveLabel(filter.label, tApp)}: {displayValue}\n </span>\n );\n out.push({\n id: `${filter.id}:${idValue}`,\n label,\n onRemove: () => {\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n },\n });\n }\n }\n return out;\n }, [listConfig.filters, pushState, state, t, tApp]);\n\n const handleClearAll = useCallback(() => {\n pushState({\n ...listDefaults,\n });\n }, [listDefaults, pushState]);\n const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false);\n const [filterSearch, setFilterSearch] = useState('');\n\n const [pickerDialog, setPickerDialog] = useState<{\n entity: string;\n whereKey: keyof Where;\n label: string;\n path?: readonly string[];\n scope?: BackofficePickerScope;\n } | null>(null);\n\n const renderFilterControl = useCallback(\n (filter: BackofficeFilterSpec<Where>): JSX.Element => {\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n const candidate = getFilterValue(filter, state.where);\n let value = '';\n if (typeof candidate === 'string') {\n value = candidate;\n }\n\n const filterLabelText = resolveLabel(filter.label, tApp);\n\n if (filter.kind === 'text') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <GlobalSearchInput\n value={value}\n onChange={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n className={styles.filterInput}\n />\n );\n }\n\n if (filter.kind === 'enum') {\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n ...filter.options.map((option) => {\n return {\n id: option.value,\n value: option.value,\n label: resolveLabel(option.label, tApp),\n };\n }),\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={value}\n onChange={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n if (filter.kind === 'boolean') {\n let current: boolean | null = null;\n if (typeof candidate === 'boolean') {\n current = candidate;\n }\n\n let selectValue = '';\n if (current === true) {\n selectValue = 'true';\n }\n if (current === false) {\n selectValue = 'false';\n }\n\n const trueLabel =\n filter.trueLabel != null\n ? resolveLabel(filter.trueLabel, tApp)\n : t('filters.boolean.yes');\n const falseLabel =\n filter.falseLabel != null\n ? resolveLabel(filter.falseLabel, tApp)\n : t('filters.boolean.no');\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n {\n id: 'true',\n value: 'true',\n label: trueLabel,\n },\n {\n id: 'false',\n value: 'false',\n label: falseLabel,\n },\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={selectValue}\n onChange={(next) => {\n let parsed: boolean | null = null;\n if (next === 'true') {\n parsed = true;\n }\n if (next === 'false') {\n parsed = false;\n }\n const nextWhere = setWhereValue(\n state.where,\n key,\n parsed,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n const pickerScope = (() => {\n if (filter.pickerScope == null) {\n return undefined;\n }\n if (typeof filter.pickerScope === 'function') {\n return filter.pickerScope(state.where);\n }\n return filter.pickerScope;\n })();\n let currentId: string | null = null;\n if (typeof candidate === 'string') {\n currentId = candidate;\n }\n\n const renderField = (displayValue: string | null = null) => {\n const normalizedDisplayValue = displayValue?.trim() ?? '';\n return (\n <EntityIdFilterField\n label={filterLabelText}\n value={currentId}\n displayValue={normalizedDisplayValue}\n onPick={() => {\n setPickerDialog({\n entity: filter.entity,\n whereKey: key,\n label: filterLabelText,\n path: filter.path,\n scope: pickerScope,\n });\n }}\n onClear={() => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n };\n\n if (currentId == null || currentId.trim() === '') {\n return renderField();\n }\n\n return (\n <EntityFilterValueText entityId={filter.entity} id={currentId}>\n {(label) => {\n return renderField(label);\n }}\n </EntityFilterValueText>\n );\n },\n [pushState, state, t, tApp],\n );\n\n const hasPlacementConfig = useMemo(() => {\n return listConfig.filters.some((filter) => {\n return filter.placement != null;\n });\n }, [listConfig.filters]);\n\n const quickFilters = useMemo(() => {\n if (listConfig.filters.length === 0) {\n return [];\n }\n if (hasPlacementConfig) {\n return listConfig.filters.filter((filter) => {\n return filter.placement === 'quick' || filter.placement === 'both';\n });\n }\n return listConfig.filters.slice(0, 3);\n }, [listConfig.filters, hasPlacementConfig]);\n\n const drawerFilters = useMemo(() => {\n return listConfig.filters.filter((filter) => {\n if (filter.placement == null) {\n return true;\n }\n return filter.placement === 'drawer' || filter.placement === 'both';\n });\n }, [listConfig.filters]);\n\n const searchFilter = useMemo(() => {\n return quickFilters.find((filter) => {\n return filter.kind === 'text';\n });\n }, [quickFilters]);\n\n const quickFiltersNode = useMemo(() => {\n const visibleQuickFilters = quickFilters.filter((filter) => {\n return filter !== searchFilter;\n });\n\n if (visibleQuickFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={styles.controlsRow}>\n {visibleQuickFilters.map((filter) => {\n return <span key={filter.id}>{renderFilterControl(filter)}</span>;\n })}\n </div>\n );\n }, [quickFilters, renderFilterControl, searchFilter]);\n\n const searchNode = useMemo(() => {\n if (searchFilter == null) {\n return null;\n }\n return renderFilterControl(searchFilter);\n }, [renderFilterControl, searchFilter]);\n\n const sortNode = useMemo(() => {\n if (listConfig.sorts.length === 0) {\n return null;\n }\n const firstSort = listConfig.sorts[0];\n if (firstSort == null) {\n return null;\n }\n const options = listConfig.sorts.map((s) => {\n return { id: s.id, value: s.id, label: resolveLabel(s.label, tApp) };\n });\n return (\n <SimpleSelect\n options={options}\n value={state.sort ?? firstSort.id}\n onChange={(next) => {\n pushState({\n ...state,\n sort: next as Sort,\n });\n }}\n />\n );\n }, [listConfig.sorts, pushState, state, tApp]);\n\n const chipsNode = useMemo(() => {\n return <FilterChipRow chips={chips} onClearAll={handleClearAll} />;\n }, [chips, handleClearAll]);\n\n const drawerSections = useMemo(() => {\n if (drawerFilters.length === 0) {\n return [];\n }\n\n const normalizedQuery = filterSearch.trim().toLowerCase();\n const items: { id: string; node: JSX.Element }[] = [];\n\n for (const filter of drawerFilters) {\n const resolvedLabel = resolveLabel(filter.label, tApp);\n const matchesQuery =\n normalizedQuery === '' ||\n resolvedLabel.toLowerCase().includes(normalizedQuery);\n\n if (matchesQuery) {\n items.push({\n id: filter.id,\n node: (\n <BackofficeFilterField label={resolvedLabel}>\n {renderFilterControl(filter)}\n </BackofficeFilterField>\n ),\n });\n }\n }\n\n if (items.length === 0) {\n return [];\n }\n\n return [\n {\n id: 'backoffice.filters.sections.default',\n title: t('filters.sections.default'),\n items,\n },\n ];\n }, [drawerFilters, filterSearch, renderFilterControl, t, tApp]);\n\n const allFiltersNode = useMemo(() => {\n if (drawerFilters.length === 0) {\n return null;\n }\n const activeCount = chips.length;\n let label = t('filters.allFilters');\n if (activeCount > 0) {\n label = t('filters.allFiltersWithCount', {\n count: activeCount,\n });\n }\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={() => {\n setIsFilterDrawerOpen(true);\n }}\n >\n {label}\n </Button>\n );\n }, [chips.length, drawerFilters.length, t]);\n\n const filterDrawerNode = (\n <BackofficeFilterDrawer\n isOpen={isFilterDrawerOpen}\n onClose={() => {\n setIsFilterDrawerOpen(false);\n setFilterSearch('');\n }}\n sections={drawerSections}\n searchValue={filterSearch}\n onSearchChange={(next) => {\n setFilterSearch(next);\n }}\n onReset={handleClearAll}\n />\n );\n\n const resolvedEmptyState = useMemo((): JSX.Element => {\n if (emptyState != null) {\n return emptyState;\n }\n\n if (isLoadingInitial) {\n return <BackofficeTableSkeleton />;\n }\n\n if (chips.length > 0) {\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmptyFiltered.description')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={handleClearAll}\n >\n {t('emptyState.listEmptyFiltered.actions.reset')}\n </Button>\n }\n />\n );\n }\n\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmpty.description')}\n />\n );\n }, [chips.length, emptyState, handleClearAll, isLoadingInitial, t]);\n\n const tableFooterMeta = useMemo(() => {\n if (typeof totalCount !== 'number') {\n return null;\n }\n return (\n <span>\n {t('list.showing', {\n shown: rows.length,\n total: totalCount,\n })}\n </span>\n );\n }, [rows.length, t, totalCount]);\n\n const headerTitle = header?.title ?? resolveLabel(listConfig.title, tApp);\n const headerSubtitle = header?.subtitle;\n\n const virtualizationConfig = useMemo(() => {\n if (!virtualize) {\n return { enabled: false, rowHeightPx: 0, overscan: 0 };\n }\n\n return { enabled: true, rowHeightPx: 52, overscan: 10 };\n }, [virtualize]);\n\n const tableInnerNode = (\n <BackofficeVirtualizedConnectionTable\n columns={columnsWithPrimary}\n rows={rows}\n getRowId={getRowId}\n emptyState={resolvedEmptyState}\n className={denseTableClass}\n gridTemplateColumns={gridTemplateColumns}\n virtualization={virtualizationConfig}\n infiniteScroll={{\n enabled: true,\n thresholdPx: 800,\n autoLoad: true,\n }}\n hasNextPage={hasNextPage}\n isLoadingMore={isLoadingMore}\n onLoadMore={onLoadMore}\n />\n );\n\n const tableNodeWithErrorBoundary = (\n <BackofficeErrorBoundary\n fallback={(args: { error: unknown; reset: () => void }) => {\n const { reset } = args;\n\n const retry = (): void => {\n reset();\n if (onRefresh != null) {\n onRefresh();\n }\n };\n\n return (\n <InlineBanner\n tone=\"danger\"\n title={t('list.errors.title')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={retry}\n >\n {t('list.actions.retry')}\n </Button>\n }\n >\n {t('list.errors.tableFailed')}\n </InlineBanner>\n );\n }}\n >\n {tableInnerNode}\n </BackofficeErrorBoundary>\n );\n\n const filtersBarNode = showFilters ? (\n <>\n <BackofficeTableToolbar\n searchSlot={searchNode}\n filtersSlot={\n <>\n {quickFiltersNode}\n {allFiltersNode}\n </>\n }\n sortSlot={sortNode}\n refreshSlot={\n <Button\n type=\"button\"\n variant=\"text\"\n size=\"small\"\n disabled={onRefresh == null}\n onClick={() => {\n if (onRefresh != null) {\n onRefresh();\n }\n }}\n >\n {t('list.actions.refresh')}\n </Button>\n }\n chipsSlot={chipsNode}\n />\n {filterDrawerNode}\n </>\n ) : null;\n\n const tableNode = (\n <div>\n {tableNodeWithErrorBoundary}\n <EntityIdPickerDialog\n isOpen={pickerDialog != null}\n entity={pickerDialog?.entity ?? config.id}\n title={pickerDialog?.label ?? t('picker.title')}\n scope={pickerDialog?.scope}\n onClose={() => {\n setPickerDialog(null);\n }}\n onSelectId={(id) => {\n if (pickerDialog == null) {\n return;\n }\n const nextWhere = setWhereValue(\n state.where,\n pickerDialog.whereKey,\n id,\n pickerDialog.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n </div>\n );\n\n const tableFooterNode = (\n <BackofficeLoadMore\n hasNextPage={hasNextPage}\n isLoading={isLoadingMore}\n meta={tableFooterMeta}\n loadMoreLabel={t('list.loadMore.more')}\n endLabel={t('list.loadMore.end')}\n loadingLabel={t('list.loadMore.loading')}\n />\n );\n\n if (variant === 'embedded') {\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <div className={styles.embeddedContainer}>\n <div className={styles.embeddedHeader}>{headerTitle}</div>\n {filtersBarNode}\n {tableNode}\n {tableFooterNode}\n </div>\n </BackofficeListFilterProvider>\n );\n }\n\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <ListPageTemplate\n headerNode={\n <BackofficePageHeader\n title={headerTitle}\n subtitle={headerSubtitle}\n actions={headerActions}\n />\n }\n toolbarNode={filtersBarNode}\n tableNode={tableNode}\n tableFooterNode={tableFooterNode}\n />\n </BackofficeListFilterProvider>\n );\n};\n\nexport default BackofficeEntityListScaffold;\n","import { Suspense, lazy, type JSX } from 'react';\n\nimport type { BackofficeEntityActionFormDialogProps } from './BackofficeEntityActionFormDialog.js';\n\nconst BackofficeEntityActionFormDialog = lazy(async () => {\n const module = await import('./BackofficeEntityActionFormDialog.js');\n return { default: module.BackofficeEntityActionFormDialog };\n});\n\nexport const LazyBackofficeEntityActionFormDialog = <Node,>(\n props: BackofficeEntityActionFormDialogProps<Node>,\n): JSX.Element => {\n const Dialog = BackofficeEntityActionFormDialog as <TNode>(\n dialogProps: BackofficeEntityActionFormDialogProps<TNode>,\n ) => JSX.Element;\n\n return (\n <Suspense fallback={null}>\n <Dialog {...props} />\n </Suspense>\n );\n};\n\nexport default LazyBackofficeEntityActionFormDialog;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { a as e, f as t, r as n, s as r } from "./loginPage.css-4M4PrzUn.js";
2
- import { t as i } from "./AuthPanel-Co626p7A.js";
1
+ import { a as e, f as t, r as n, s as r } from "./loginPage.css-CBJ1Ozm5.js";
2
+ import { t as i } from "./AuthPanel-DiHejPoq.js";
3
3
  import { useCallback as a, useMemo as o, useState as s } from "react";
4
4
  import { AuthLayout as c, Button as l, FormError as u, FormField as d } from "@plumile/ui";
5
5
  import { jsx as f, jsxs as p } from "react/jsx-runtime";
@@ -100,4 +100,4 @@ var m = 8, h = ({ onBackToLogin: h, onCompletePasswordReset: g, token: _ }) => {
100
100
  //#endregion
101
101
  export { h as t };
102
102
 
103
- //# sourceMappingURL=PasswordResetCompleteScreen-DdJsdKMI.js.map
103
+ //# sourceMappingURL=PasswordResetCompleteScreen-B0P_tZg2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordResetCompleteScreen-DdJsdKMI.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 { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\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 } = useSharedTranslation();\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 className={styles.formSurface} onSubmit={handleSubmit} noValidate>\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":";;;;;;AAeA,IAAM,IAAsB,GAWf,KAA+B,EAC1C,kBACA,4BACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAAsB,EAC9B,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAiB,KAAsB,EAAS,GAAG,EACpD,CAAC,GAAQ,KAAa,EAA+B,OAAO,EAC5D,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAEM,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC,EAEL,IAAe,GAClB,MAAsC;AAIrC,MAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,MAAkB,IAAI;AACxB,KAAS,EAAE,iDAAiD,CAAC;AAC7D;;AAGF,MAAI,EAAS,SAAS,GAAqB;AACzC,KACE,EAAE,+CAA+C,EAC/C,WAAW,GACZ,CAAC,CACH;AACD;;AAGF,MAAI,MAAa,GAAiB;AAChC,KAAS,EAAE,6CAA6C,CAAC;AACzD;;AA2BF,EAxBA,EAAgB,GAAK,GAES,YAA2B;AACvD,OAAI;AAKF,IAJgB,MAAM,EAAwB;KAC5C,aAAa;KACb,OAAO;KACR,CAAC,GAEA,EAAU,YAAY,GAEtB,EAAS,EAAE,4CAA4C,CAAC;YAEnD,GAAe;AACtB,MACE,aAAyB,QACrB,EAAc,UACd,EAAE,4CAA4C,CACnD;aACO;AACR,MAAgB,GAAM;;MAIH,CAAC,YAAY,GAElC;IAEJ;EAAC;EAAyB;EAAU;EAAiB;EAAe;EAAE,CACvE,EAEG;AAoEJ,QAnEA,AAsBE,IAtBE,MAAW,cAEX,kBAAC,GAAD;EACE,OAAO,EAAE,2CAA2C;EACpD,aAAa,EAAE,iDAAiD;EAChE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,WAAW;GACX,SAAS;aAER,EAAE,4CAA4C;GACxC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,4CAA4C;GAC7C,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EACE,OAAO,EAAE,wCAAwC;EACjD,aAAa,EAAE,8CAA8C;YAE7D,kBAAC,QAAD;GAAM,WAAW;GAAoB,UAAU;GAAc,YAAA;aAA7D;IACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,gDAAgD;KACzD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAY,EAAM,OAAO,MAAM,EAC/B,EAAS,KAAK;;KAEhB,aAAa,EACX,sDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KACE,OAAO,EAAE,+CAA+C;KACxD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAmB,EAAM,OAAO,MAAM,EACtC,EAAS,KAAK;;KAEhB,aAAa,EACX,qDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,yCAAyC;KACrC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EACE,OAAO,EAAE,mCAAmC;EAC5C,UAAU,EAAE,sCAAsC;YAEjD;EACU,CAAA"}
1
+ {"version":3,"file":"PasswordResetCompleteScreen-B0P_tZg2.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 { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\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 } = useSharedTranslation();\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 className={styles.formSurface} onSubmit={handleSubmit} noValidate>\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":";;;;;;AAeA,IAAM,IAAsB,GAWf,KAA+B,EAC1C,kBACA,4BACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAAsB,EAC9B,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAiB,KAAsB,EAAS,GAAG,EACpD,CAAC,GAAQ,KAAa,EAA+B,OAAO,EAC5D,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAEM,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC,EAEL,IAAe,GAClB,MAAsC;AAIrC,MAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,MAAkB,IAAI;AACxB,KAAS,EAAE,iDAAiD,CAAC;AAC7D;;AAGF,MAAI,EAAS,SAAS,GAAqB;AACzC,KACE,EAAE,+CAA+C,EAC/C,WAAW,GACZ,CAAC,CACH;AACD;;AAGF,MAAI,MAAa,GAAiB;AAChC,KAAS,EAAE,6CAA6C,CAAC;AACzD;;AA2BF,EAxBA,EAAgB,GAAK,GAES,YAA2B;AACvD,OAAI;AAKF,IAJgB,MAAM,EAAwB;KAC5C,aAAa;KACb,OAAO;KACR,CAAC,GAEA,EAAU,YAAY,GAEtB,EAAS,EAAE,4CAA4C,CAAC;YAEnD,GAAe;AACtB,MACE,aAAyB,QACrB,EAAc,UACd,EAAE,4CAA4C,CACnD;aACO;AACR,MAAgB,GAAM;;MAIH,CAAC,YAAY,GAElC;IAEJ;EAAC;EAAyB;EAAU;EAAiB;EAAe;EAAE,CACvE,EAEG;AAoEJ,QAnEA,AAsBE,IAtBE,MAAW,cAEX,kBAAC,GAAD;EACE,OAAO,EAAE,2CAA2C;EACpD,aAAa,EAAE,iDAAiD;EAChE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,WAAW;GACX,SAAS;aAER,EAAE,4CAA4C;GACxC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,4CAA4C;GAC7C,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EACE,OAAO,EAAE,wCAAwC;EACjD,aAAa,EAAE,8CAA8C;YAE7D,kBAAC,QAAD;GAAM,WAAW;GAAoB,UAAU;GAAc,YAAA;aAA7D;IACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,gDAAgD;KACzD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAY,EAAM,OAAO,MAAM,EAC/B,EAAS,KAAK;;KAEhB,aAAa,EACX,sDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KACE,OAAO,EAAE,+CAA+C;KACxD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAmB,EAAM,OAAO,MAAM,EACtC,EAAS,KAAK;;KAEhB,aAAa,EACX,qDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,yCAAyC;KACrC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EACE,OAAO,EAAE,mCAAmC;EAC5C,UAAU,EAAE,sCAAsC;YAEjD;EACU,CAAA"}
@@ -1,5 +1,5 @@
1
- import { a as e, f as t, s as n } from "./loginPage.css-4M4PrzUn.js";
2
- import { t as r } from "./AuthPanel-Co626p7A.js";
1
+ import { a as e, f as t, s as n } from "./loginPage.css-CBJ1Ozm5.js";
2
+ import { t as r } from "./AuthPanel-DiHejPoq.js";
3
3
  import { useCallback as i, useMemo as a, useState as o } from "react";
4
4
  import { AuthLayout as s, Button as c, FormError as l, FormField as u } from "@plumile/ui";
5
5
  import { jsx as d, jsxs as f } from "react/jsx-runtime";
@@ -81,4 +81,4 @@ var p = ({ onStartPasswordReset: p }) => {
81
81
  //#endregion
82
82
  export { p as t };
83
83
 
84
- //# sourceMappingURL=PasswordResetRequestScreen-DBIHOmsl.js.map
84
+ //# sourceMappingURL=PasswordResetRequestScreen-p9s0dblR.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PasswordResetRequestScreen-DBIHOmsl.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 { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\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 } = useSharedTranslation();\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 className={styles.formSurface} onSubmit={handleSubmit} noValidate>\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 autoFocus\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":";;;;;;AAsBA,IAAa,KAA8B,EACzC,8BACwB;CACxB,IAAM,EAAE,SAAM,SAAM,GAAsB,EACpC,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,CAAC,GAAQ,KAAa,EAA0B,OAAO,EACvD,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAS,QAAc;EAC3B,IAAM,IAAW,EAAK,SAAS,MAAM;AACrC,MAAI,MAAa,GACf,QAAO;AAEL,eAAO,YAAc,KAGzB,QAAO,UAAU;IAChB,CAAC,EAAK,SAAS,CAAC,EAEb,IAAe,GAClB,MAAsC;AAIrC,MAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,EAAM,MAAM,KAAK,IAAI;AACvB,KAAS,EAAE,iDAAiD,CAAC;AAC7D;;AAIF,EADA,EAAgB,GAAK,EACrB,EAAqB;GACnB,OAAO,EAAM,MAAM;GACnB;GACD,CAAC,CACC,MAAM,MAAY;AACjB,GAAI,IACF,EAAU,OAAO,GAEjB,EAAS,EAAE,+CAA+C,CAAC;IAE7D,CACD,OAAO,MAAkB;AACxB,KACE,aAAyB,QACrB,EAAc,UACd,EAAE,+CAA+C,CACtD;IACD,CACD,cAAc;AACb,KAAgB,GAAM;IACtB;IAEN;EAAC;EAAO;EAAQ;EAAsB;EAAE,CACzC,EAEG;AAkDJ,QAjDA,AAuBE,IAvBE,MAAW,SAEX,kBAAC,GAAD;EACE,OAAO,EAAE,uCAAuC;EAChD,aAAa,EAAE,8CAA8C,EAAE,UAAO,CAAC;EACvE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,eAAe;AACb,MAAU,OAAO;;aAGlB,EAAE,wCAAwC;GACpC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,wCAAwC;GACzC,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EAAW,aAAa,EAAE,6CAA6C;YACrE,kBAAC,QAAD;GAAM,WAAW;GAAoB,UAAU;GAAc,YAAA;aAA7D;IACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,4CAA4C;KACrD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAS,EAAM,OAAO,MAAM,EAC5B,EAAS,KAAK;;KAEhB,aAAa,EAAE,kDAAkD;KACjE,cAAa;KACb,WAAA;KACA,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,wCAAwC;KACpC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EAAY,OAAO,EAAE,kCAAkC;YACpD;EACU,CAAA"}
1
+ {"version":3,"file":"PasswordResetRequestScreen-p9s0dblR.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 { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\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 } = useSharedTranslation();\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 className={styles.formSurface} onSubmit={handleSubmit} noValidate>\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 autoFocus\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":";;;;;;AAsBA,IAAa,KAA8B,EACzC,8BACwB;CACxB,IAAM,EAAE,SAAM,SAAM,GAAsB,EACpC,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,CAAC,GAAQ,KAAa,EAA0B,OAAO,EACvD,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAS,QAAc;EAC3B,IAAM,IAAW,EAAK,SAAS,MAAM;AACrC,MAAI,MAAa,GACf,QAAO;AAEL,eAAO,YAAc,KAGzB,QAAO,UAAU;IAChB,CAAC,EAAK,SAAS,CAAC,EAEb,IAAe,GAClB,MAAsC;AAIrC,MAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,EAAM,MAAM,KAAK,IAAI;AACvB,KAAS,EAAE,iDAAiD,CAAC;AAC7D;;AAIF,EADA,EAAgB,GAAK,EACrB,EAAqB;GACnB,OAAO,EAAM,MAAM;GACnB;GACD,CAAC,CACC,MAAM,MAAY;AACjB,GAAI,IACF,EAAU,OAAO,GAEjB,EAAS,EAAE,+CAA+C,CAAC;IAE7D,CACD,OAAO,MAAkB;AACxB,KACE,aAAyB,QACrB,EAAc,UACd,EAAE,+CAA+C,CACtD;IACD,CACD,cAAc;AACb,KAAgB,GAAM;IACtB;IAEN;EAAC;EAAO;EAAQ;EAAsB;EAAE,CACzC,EAEG;AAkDJ,QAjDA,AAuBE,IAvBE,MAAW,SAEX,kBAAC,GAAD;EACE,OAAO,EAAE,uCAAuC;EAChD,aAAa,EAAE,8CAA8C,EAAE,UAAO,CAAC;EACvE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,eAAe;AACb,MAAU,OAAO;;aAGlB,EAAE,wCAAwC;GACpC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,wCAAwC;GACzC,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EAAW,aAAa,EAAE,6CAA6C;YACrE,kBAAC,QAAD;GAAM,WAAW;GAAoB,UAAU;GAAc,YAAA;aAA7D;IACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,4CAA4C;KACrD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAS,EAAM,OAAO,MAAM,EAC5B,EAAS,KAAK;;KAEhB,aAAa,EAAE,kDAAkD;KACjE,cAAa;KACb,WAAA;KACA,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,wCAAwC;KACpC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EAAY,OAAO,EAAE,kCAAkC;YACpD;EACU,CAAA"}
@@ -1,4 +1,4 @@
1
- import { d as e, f as t, s as n } from "./loginPage.css-4M4PrzUn.js";
1
+ import { d as e, f as t, s as n } from "./loginPage.css-CBJ1Ozm5.js";
2
2
  import { useEffect as r, useMemo as i, useState as a } from "react";
3
3
  import { AuthLayout as o, Button as s, FormError as c } from "@plumile/ui";
4
4
  import { jsx as l, jsxs as u } from "react/jsx-runtime";
@@ -61,4 +61,4 @@ var d = ({ onBackToLogin: d, onVerifyEmail: f, token: p }) => {
61
61
  //#endregion
62
62
  export { d as t };
63
63
 
64
- //# sourceMappingURL=VerifyEmailScreen-C9rfi3q8.js.map
64
+ //# sourceMappingURL=VerifyEmailScreen--9lxOGlW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VerifyEmailScreen-C9rfi3q8.js","names":[],"sources":["../../src/auth/pages/VerifyEmailScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { useEffect, useMemo, useState, type JSX } from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError } from '@plumile/ui';\n\nimport * as styles from '../login/loginPage.css.js';\n\ntype VerificationState = 'pending' | 'success' | 'error';\n\ntype Props = {\n onBackToLogin: () => void;\n onVerifyEmail: (input: { token: string }) => Promise<boolean>;\n token?: string;\n};\n\nexport const VerifyEmailScreen = ({\n onBackToLogin,\n onVerifyEmail,\n token,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const [state, setState] = useState<VerificationState>('pending');\n const [error, setError] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n useEffect(() => {\n if (resolvedToken === '') {\n setState('error');\n setError(t('auth.verifyEmail.errors.missingToken'));\n return;\n }\n\n const verifyEmail = async (): Promise<void> => {\n try {\n const success = await onVerifyEmail({ token: resolvedToken });\n if (success) {\n setState('success');\n } else {\n setState('error');\n setError(t('auth.verifyEmail.errors.invalid'));\n }\n } catch (mutationError) {\n setState('error');\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.verifyEmail.errors.invalid'),\n );\n }\n };\n\n verifyEmail().catch(() => {\n return undefined;\n });\n }, [onVerifyEmail, resolvedToken, t]);\n\n let content: JSX.Element;\n if (state === 'success') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.verifyEmail.status.success')}</p>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.continue')}\n </Button>\n </div>\n );\n } else if (state === 'error') {\n content = (\n <div className={styles.stack}>\n {error != null ? <FormError>{error}</FormError> : null}\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.return')}\n </Button>\n </div>\n );\n } else {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.verifyEmail.status.verifying')}\n </p>\n <Button type=\"button\" isLoading>\n {t('auth.verifyEmail.status.verifyingButton')}\n </Button>\n </div>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.verifyEmail.title')}\n subtitle={t('auth.verifyEmail.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;AAgBA,IAAa,KAAqB,EAChC,kBACA,kBACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAAsB,EAC9B,CAAC,GAAO,KAAY,EAA4B,UAAU,EAC1D,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAEM,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC;AAEX,SAAgB;AACd,MAAI,MAAkB,IAAI;AAExB,GADA,EAAS,QAAQ,EACjB,EAAS,EAAE,uCAAuC,CAAC;AACnD;;AAsBF,GAnBoB,YAA2B;AAC7C,OAAI;AAEF,IADgB,MAAM,EAAc,EAAE,OAAO,GAAe,CAAC,GAE3D,EAAS,UAAU,IAEnB,EAAS,QAAQ,EACjB,EAAS,EAAE,kCAAkC,CAAC;YAEzC,GAAe;AAEtB,IADA,EAAS,QAAQ,EACjB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,kCAAkC,CACzC;;MAIQ,CAAC,YAAY,GAExB;IACD;EAAC;EAAe;EAAe;EAAE,CAAC;CAErC,IAAI;AAgCJ,QA/BA,AAmBE,IAnBE,MAAU,YAEV,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aAAgB,EAAE,kCAAkC;GAAK,CAAA,EACvE,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,oCAAoC;GAChC,CAAA,CACL;MAEC,MAAU,UAEjB,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA,EAC/C,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,kCAAkC;GAC9B,CAAA,CACL;MAIN,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,oCAAoC;GACrC,CAAA,EACJ,kBAAC,GAAD;GAAQ,MAAK;GAAS,WAAA;aACnB,EAAE,0CAA0C;GACtC,CAAA,CACL;KAKR,kBAAC,GAAD;EACE,OAAO,EAAE,yBAAyB;EAClC,UAAU,EAAE,4BAA4B;YAEvC;EACU,CAAA"}
1
+ {"version":3,"file":"VerifyEmailScreen--9lxOGlW.js","names":[],"sources":["../../src/auth/pages/VerifyEmailScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { useEffect, useMemo, useState, type JSX } from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError } from '@plumile/ui';\n\nimport * as styles from '../login/loginPage.css.js';\n\ntype VerificationState = 'pending' | 'success' | 'error';\n\ntype Props = {\n onBackToLogin: () => void;\n onVerifyEmail: (input: { token: string }) => Promise<boolean>;\n token?: string;\n};\n\nexport const VerifyEmailScreen = ({\n onBackToLogin,\n onVerifyEmail,\n token,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const [state, setState] = useState<VerificationState>('pending');\n const [error, setError] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n useEffect(() => {\n if (resolvedToken === '') {\n setState('error');\n setError(t('auth.verifyEmail.errors.missingToken'));\n return;\n }\n\n const verifyEmail = async (): Promise<void> => {\n try {\n const success = await onVerifyEmail({ token: resolvedToken });\n if (success) {\n setState('success');\n } else {\n setState('error');\n setError(t('auth.verifyEmail.errors.invalid'));\n }\n } catch (mutationError) {\n setState('error');\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.verifyEmail.errors.invalid'),\n );\n }\n };\n\n verifyEmail().catch(() => {\n return undefined;\n });\n }, [onVerifyEmail, resolvedToken, t]);\n\n let content: JSX.Element;\n if (state === 'success') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.verifyEmail.status.success')}</p>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.continue')}\n </Button>\n </div>\n );\n } else if (state === 'error') {\n content = (\n <div className={styles.stack}>\n {error != null ? <FormError>{error}</FormError> : null}\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.return')}\n </Button>\n </div>\n );\n } else {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.verifyEmail.status.verifying')}\n </p>\n <Button type=\"button\" isLoading>\n {t('auth.verifyEmail.status.verifyingButton')}\n </Button>\n </div>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.verifyEmail.title')}\n subtitle={t('auth.verifyEmail.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;AAgBA,IAAa,KAAqB,EAChC,kBACA,kBACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAAsB,EAC9B,CAAC,GAAO,KAAY,EAA4B,UAAU,EAC1D,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAEM,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC;AAEX,SAAgB;AACd,MAAI,MAAkB,IAAI;AAExB,GADA,EAAS,QAAQ,EACjB,EAAS,EAAE,uCAAuC,CAAC;AACnD;;AAsBF,GAnBoB,YAA2B;AAC7C,OAAI;AAEF,IADgB,MAAM,EAAc,EAAE,OAAO,GAAe,CAAC,GAE3D,EAAS,UAAU,IAEnB,EAAS,QAAQ,EACjB,EAAS,EAAE,kCAAkC,CAAC;YAEzC,GAAe;AAEtB,IADA,EAAS,QAAQ,EACjB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,kCAAkC,CACzC;;MAIQ,CAAC,YAAY,GAExB;IACD;EAAC;EAAe;EAAe;EAAE,CAAC;CAErC,IAAI;AAgCJ,QA/BA,AAmBE,IAnBE,MAAU,YAEV,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aAAgB,EAAE,kCAAkC;GAAK,CAAA,EACvE,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,oCAAoC;GAChC,CAAA,CACL;MAEC,MAAU,UAEjB,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA,EAC/C,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,kCAAkC;GAC9B,CAAA,CACL;MAIN,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,oCAAoC;GACrC,CAAA,EACJ,kBAAC,GAAD;GAAQ,MAAK;GAAS,WAAA;aACnB,EAAE,0CAA0C;GACtC,CAAA,CACL;KAKR,kBAAC,GAAD;EACE,OAAO,EAAE,yBAAyB;EAClC,UAAU,EAAE,4BAA4B;YAEvC;EACU,CAAA"}
@@ -2,22 +2,22 @@ import { i as e, n as t, r as n, t as r } from "./environment-BJeJTbIN.js";
2
2
  import { t as i } from "./useRelayEnvironment-vQ86aW-n.js";
3
3
  import { n as a, t as o } from "./BackofficeConfigContext-R0t1owTI.js";
4
4
  import { i as s, t as c } from "./sidebarUtils-CuwJ_3mD.js";
5
- import { f as l } from "./loginPage.css-4M4PrzUn.js";
6
- import { a as u, i as d, n as f, r as p, t as m } from "./useAuth-tQWc1NnB.js";
7
- import { n as h, t as g } from "./synchronizeAuthStatusQuery-Bb5wh5rF.js";
8
- import "./AuthPanel-Co626p7A.js";
9
- import { t as _ } from "./AcceptInvitationScreen-DJkNNx49.js";
10
- import { t as v } from "./PasswordResetCompleteScreen-DdJsdKMI.js";
11
- import { t as y } from "./PasswordResetRequestScreen-DBIHOmsl.js";
12
- import { t as ee } from "./VerifyEmailScreen-C9rfi3q8.js";
5
+ import { f as l } from "./loginPage.css-CBJ1Ozm5.js";
6
+ import { a as u, i as d, n as f, r as p, t as m } from "./useAuth-CjdysxLB.js";
7
+ import { n as h, t as g } from "./synchronizeAuthStatusQuery-Dr6AEFhi.js";
8
+ import "./AuthPanel-DiHejPoq.js";
9
+ import { t as _ } from "./AcceptInvitationScreen-5-0EtE15.js";
10
+ import { t as v } from "./PasswordResetCompleteScreen-B0P_tZg2.js";
11
+ import { t as y } from "./PasswordResetRequestScreen-p9s0dblR.js";
12
+ import { t as ee } from "./VerifyEmailScreen--9lxOGlW.js";
13
13
  import { n as te, t as b } from "./useBackofficeReactTranslation-WfXU8kCf.js";
14
- import { i as ne, n as re, t as x } from "./EntityFilterValue-Bn9VGr2M.js";
15
- import { i as ie, t as ae } from "./EntityIdPickerDialog-D_qAlrU6.js";
16
- import { a as oe, i as se, r as ce, t as le } from "./BackofficeDetailPayload-CbsZKnw6.js";
14
+ import { i as ne, n as re, t as x } from "./EntityFilterValue-B5ZGHO_u.js";
15
+ import { i as ie, t as ae } from "./EntityIdPickerDialog-DbTnDU4v.js";
16
+ import { a as oe, i as se, r as ce, t as le } from "./BackofficeDetailPayload-iVx66o_6.js";
17
17
  import { t as ue } from "./useBackofficeListUrlState-D4fx5O7u.js";
18
18
  import { i as de, n as fe, r as pe, t as me } from "./mutationResult-CcQMY13J.js";
19
19
  import { t as he } from "./pageResolution-hAQA5C6S.js";
20
- import { n as ge, t as _e } from "./BackofficeRightPageLayout-D7QRE8KZ.js";
20
+ import { n as ge, t as _e } from "./BackofficeRightPageLayout-F8ipegrl.js";
21
21
  import "./BackofficeTopbarPortalContext-iD7dm4_h.js";
22
22
  import { StrictMode as ve, useCallback as S, useContext as ye, useEffect as C, useMemo as w, useRef as be, useState as T } from "react";
23
23
  import { createInstance as E } from "i18next";
@@ -998,7 +998,7 @@ var Je = {
998
998
  }, { RelayEnvironmentProvider: Ye } = k, Xe = ({ children: e }) => /* @__PURE__ */ A(Ye, {
999
999
  environment: t(),
1000
1000
  children: e
1001
- }), { loadQuery: L, usePreloadedQuery: Ze } = k, Qe = O("WrapperPage", async () => ({ default: (await import("@plumile/ui")).WrapperPage })), $e = O("BackofficeLayoutPage", async () => import("./BackofficeLayoutPage-DpvTzwtK.js")), et = O("BackofficeEntityListPage", async () => import("./BackofficeEntityListPage-CtLI15-L.js")), tt = O("BackofficeEntityDetailPage", async () => import("./BackofficeEntityDetailPage-CE4tl5ZJ.js")), nt = O("BackofficeEntityDetailLayoutPage", async () => import("./BackofficeEntityDetailLayoutPage-DXjRqvcZ.js")), rt = O("BackofficeEntityDetailUnknownPageRedirect", async () => import("./BackofficeEntityDetailUnknownPageRedirect-DRWTeox-.js")), it = O("BackofficeDashboardPage", async () => import("./BackofficeDashboardPage-B5_YC1ZL.js")), at = O("BackofficeLoginPage", async () => import("./BackofficeLoginPage-GKVdZndS.js")), ot = O("BackofficePasswordResetRequestPage", async () => import("./BackofficePasswordResetRequestPage-Df8mcLkC.js")), st = O("BackofficePasswordResetCompletePage", async () => import("./BackofficePasswordResetCompletePage-CCQJYK9S.js")), ct = O("BackofficeVerifyEmailPage", async () => import("./BackofficeVerifyEmailPage-CtqLzXAD.js")), lt = O("BackofficeAcceptInvitationPage", async () => import("./BackofficeAcceptInvitationPage-BQfDMSux.js")), ut = (e) => {
1001
+ }), { loadQuery: L, usePreloadedQuery: Ze } = k, Qe = O("WrapperPage", async () => ({ default: (await import("@plumile/ui")).WrapperPage })), $e = O("BackofficeLayoutPage", async () => import("./BackofficeLayoutPage-Da4y2B0i.js")), et = O("BackofficeEntityListPage", async () => import("./BackofficeEntityListPage-BneDsGo-.js")), tt = O("BackofficeEntityDetailPage", async () => import("./BackofficeEntityDetailPage-BljQmWsw.js")), nt = O("BackofficeEntityDetailLayoutPage", async () => import("./BackofficeEntityDetailLayoutPage-DXjRqvcZ.js")), rt = O("BackofficeEntityDetailUnknownPageRedirect", async () => import("./BackofficeEntityDetailUnknownPageRedirect-DRWTeox-.js")), it = O("BackofficeDashboardPage", async () => import("./BackofficeDashboardPage-C7lIVeA1.js")), at = O("BackofficeLoginPage", async () => import("./BackofficeLoginPage-Dc61SyMV.js")), ot = O("BackofficePasswordResetRequestPage", async () => import("./BackofficePasswordResetRequestPage-DDNcCf3_.js")), st = O("BackofficePasswordResetCompletePage", async () => import("./BackofficePasswordResetCompletePage-CvoHqhBS.js")), ct = O("BackofficeVerifyEmailPage", async () => import("./BackofficeVerifyEmailPage-BSTtLXdx.js")), lt = O("BackofficeAcceptInvitationPage", async () => import("./BackofficeAcceptInvitationPage-FPbn31YK.js")), ut = (e) => {
1002
1002
  let t = e.trim();
1003
1003
  return t === "" || t === "/" ? "" : t.replace(/^\/+|\/+$/g, "");
1004
1004
  }, dt = (e) => {
@@ -1263,7 +1263,7 @@ function ht(e) {
1263
1263
  }
1264
1264
  //#endregion
1265
1265
  //#region src/components/backoffice/routing/backofficeRouteFallback.css.ts
1266
- var gt = "txvbqb9io txvbqbai6 txvbqbco txvbqbdnx txvbqbk4o txvbqbu6f txvbqbaoo txvbqbv2t txvbqbv8r", _t = "txvbqbv8t", vt = () => {
1266
+ var gt = "txvbqb9ip txvbqbai7 txvbqbcp txvbqbdoy txvbqbk5p txvbqbu7g txvbqbaop txvbqbv43 txvbqbva1", _t = "txvbqbva3", vt = () => {
1267
1267
  let { t: e, i18n: t } = D("backofficeReact", { useSuspense: !1 }), n = "Loading...";
1268
1268
  return t.isInitialized && (n = e("common.loading")), /* @__PURE__ */ j("div", {
1269
1269
  className: gt,
@@ -1275,7 +1275,7 @@ var gt = "txvbqb9io txvbqbai6 txvbqbco txvbqbdnx txvbqbk4o txvbqbu6f txvbqbaoo t
1275
1275
  children: n
1276
1276
  })]
1277
1277
  });
1278
- }, yt = "_11exksg1 txvbqbv2v txvbqbpso txvbqbt6x txvbqbdpf txvbqbl6f txvbqb2k txvbqbu6f txvbqbuvf", bt = "_11exksg2 txvbqbcff txvbqbunf", xt = () => /* @__PURE__ */ A("div", {
1278
+ }, yt = "_11exksg1 txvbqbv45 txvbqbptp txvbqbt7y txvbqbdqg txvbqbl7g txvbqb2k txvbqbu7g txvbqbuwp", bt = "_11exksg2 txvbqbcgg txvbqbuog", xt = () => /* @__PURE__ */ A("div", {
1279
1279
  className: yt,
1280
1280
  "aria-hidden": "true",
1281
1281
  children: /* @__PURE__ */ A("div", { className: bt })
@@ -1527,7 +1527,7 @@ function Mt(e, t) {
1527
1527
  }
1528
1528
  //#endregion
1529
1529
  //#region src/components/backoffice/filters/backofficeFilterAction.css.ts
1530
- var Nt = "hwnq700 txvbqb9jf txvbqbco txvbqbdnx txvbqbtwo txvbqbc66 txvbqbl9f txvbqb1qx txvbqb1co txvbqb1qf txvbqbf6 txvbqbuzj txvbqbv8r txvbqbv txvbqb3b txvbqb78 txvbqb6w txvbqb7k", Pt = "txvbqbtw6 txvbqbc5o", Ft = (e, t) => e(t), It = (e) => {
1530
+ var Nt = "hwnq700 txvbqb9jg txvbqbcp txvbqbdoy txvbqbtxp txvbqbc6p txvbqblag txvbqb1qy txvbqb1cp txvbqb1qg txvbqbf7 txvbqbv0t txvbqbva1 txvbqbv txvbqb3b txvbqb78 txvbqb6w txvbqb7k", Pt = "txvbqbtx7 txvbqbc67", Ft = (e, t) => e(t), It = (e) => {
1531
1531
  let { t } = D(), { t: n } = b(), { filterColumnAliases: r } = a(), { whereKey: i, value: o, path: s, label: c, listConfig: l } = e, u = ne(), d = null;
1532
1532
  if (l == null ? u != null && (d = u.config) : d = l, d == null) return null;
1533
1533
  let f = $(d, i, s);
@@ -1554,7 +1554,7 @@ var Nt = "hwnq700 txvbqb9jf txvbqbco txvbqbdnx txvbqbtwo txvbqbc66 txvbqbl9f txv
1554
1554
  className: Nt,
1555
1555
  children: h
1556
1556
  });
1557
- }, Lt = "txvbqb9io txvbqbai6 txvbqbap6", Rt = "txvbqb9io txvbqbai6 txvbqbaoo", zt = "txvbqb9ix txvbqbbwx txvbqbap6 txvbqbcf", Bt = "txvbqb9io txvbqbai6 txvbqbap6", Vt = "txvbqb9io txvbqbai6 txvbqbap6", Ht = ({ summary: e, aside: t, children: n, className: r }) => {
1557
+ }, Lt = "txvbqb9ip txvbqbai7 txvbqbap7", Rt = "txvbqb9ip txvbqbai7 txvbqbaop", zt = "txvbqb9iy txvbqbbwy txvbqbap7 txvbqbcg", Bt = "txvbqb9ip txvbqbai7 txvbqbap7", Vt = "txvbqb9ip txvbqbai7 txvbqbap7", Ht = ({ summary: e, aside: t, children: n, className: r }) => {
1558
1558
  let i = null;
1559
1559
  e != null && (i = /* @__PURE__ */ A("div", {
1560
1560
  className: Rt,
@@ -1576,7 +1576,7 @@ var Nt = "hwnq700 txvbqb9jf txvbqbco txvbqbdnx txvbqbtwo txvbqbc66 txvbqbl9f txv
1576
1576
  children: [o, a]
1577
1577
  })]
1578
1578
  });
1579
- }, Ut = "txvbqbv8p txvbqb3d txvbqbvvh", Wt = ({ count: e, entity: t, where: n }) => {
1579
+ }, Ut = "txvbqbv9z txvbqb3d txvbqbvwr", Wt = ({ count: e, entity: t, where: n }) => {
1580
1580
  let { entities: r, entityRegistry: i } = a(), o = ye(Ee), s = 0;
1581
1581
  typeof e == "number" && Number.isFinite(e) && (s = e);
1582
1582
  let c = r[t];
@@ -1618,7 +1618,7 @@ var Nt = "hwnq700 txvbqb9jf txvbqbco txvbqbdnx txvbqbtwo txvbqbc66 txvbqbl9f txv
1618
1618
  },
1619
1619
  children: s
1620
1620
  });
1621
- }, Gt = "txvbqb9io", Kt = "txvbqb9io txvbqbai6 txvbqbaoo", qt = ({ headerNode: e, tabs: t, activeId: n, children: r }) => {
1621
+ }, Gt = "txvbqb9ip", Kt = "txvbqb9ip txvbqbai7 txvbqbaop", qt = ({ headerNode: e, tabs: t, activeId: n, children: r }) => {
1622
1622
  let i = null;
1623
1623
  return t != null && t.length > 1 && n != null && (i = /* @__PURE__ */ A(ke, {
1624
1624
  items: t,
@@ -1633,7 +1633,7 @@ var Nt = "hwnq700 txvbqb9jf txvbqbco txvbqbdnx txvbqbtwo txvbqbc66 txvbqbl9f txv
1633
1633
  children: r
1634
1634
  })
1635
1635
  });
1636
- }, Jt = "txvbqb9jf txvbqbco txvbqbanx txvbqbajx", Yt = ({ children: e, className: t }) => /* @__PURE__ */ A("span", {
1636
+ }, Jt = "txvbqb9jg txvbqbcp txvbqbany txvbqbajy", Yt = ({ children: e, className: t }) => /* @__PURE__ */ A("span", {
1637
1637
  className: Pe(Jt, t),
1638
1638
  children: e
1639
1639
  });
@@ -0,0 +1,12 @@
1
+ import { useTranslation as e } from "react-i18next";
2
+ //#region src/i18n/useSharedTranslation.ts
3
+ function t() {
4
+ return e("shared");
5
+ }
6
+ //#endregion
7
+ //#region src/auth/login/loginPage.css.ts
8
+ var n = "txvbqb9ip txvbqbai7 txvbqbaop", r = "txvbqb9ip txvbqbai7 txvbqbu7g", i = "txvbqbvbd txvbqb8y txvbqbfcp txvbqbf5y", a = "txvbqbcp txvbqb9ip txvbqbajy txvbqbaog txvbqbdpp txvbqbhyg", o = "w8yhmy0 txvbqbvaz txvbqbamp txvbqb78 txvbqb6x txvbqb7k", s = "txvbqbnwy txvbqbok7 txvbqbp7g txvbqblz7 txvbqb767 txvbqb73g txvbqb7d7 txvbqb7ag", c = "txvbqb9ip txvbqbai7 txvbqbaop", l = "txvbqbu7g", u = "txvbqbfcp txvbqb9p txvbqbamy txvbqbvaz txvbqbee7", d = "txvbqbhyp", f = "w8yhmy1 txvbqb107 txvbqb1dg txvbqb1qg txvbqbvaz txvbqbv5t txvbqb78 txvbqb6w txvbqb7k";
9
+ //#endregion
10
+ export { r as a, o as c, n as d, t as f, d as i, s as l, c as n, l as o, f as r, i as s, a as t, u };
11
+
12
+ //# sourceMappingURL=loginPage.css-CBJ1Ozm5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"loginPage.css-4M4PrzUn.js","names":[],"sources":["../../src/i18n/useSharedTranslation.ts","../../src/auth/login/loginPage.css.ts"],"sourcesContent":["import { useTranslation } from 'react-i18next';\n\n/** Returns i18n helpers bound to the shared namespace. */\nexport function useSharedTranslation(): ReturnType<typeof useTranslation> {\n return useTranslation('shared');\n}\n","import { style } from '@vanilla-extract/css';\nimport { sprinkles, vars } from '@plumile/ui';\n\nexport const stack = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const formSurface = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n width: 'full',\n});\n\nexport const helper = sprinkles({\n color: 'brandDarkGray',\n fontSize: 'sm',\n margin: 0,\n lineHeight: 1.6,\n});\n\nexport const divider = sprinkles({\n alignItems: 'center',\n color: 'brandDarkGray',\n display: 'flex',\n gap: 2,\n marginTop: 5,\n marginBottom: 3,\n});\n\nexport const dividerLine = sprinkles({\n backgroundColor: 'brandPrimaryRed',\n height: 'px',\n flex: 1,\n borderRadius: 'full',\n opacity: 35,\n});\n\nexport const actionsRow = sprinkles({\n alignItems: 'center',\n display: 'flex',\n flexWrap: 'wrap',\n gap: 3,\n justifyContent: 'space-between',\n marginTop: 3,\n});\n\nexport const inlineLink = style([\n sprinkles({\n color: 'brandPrimaryRed',\n fontWeight: 'semibold',\n transitionProperty: 'colors',\n transitionDuration: 150,\n transitionTimingFunction: 'ease',\n }),\n {\n background: 'transparent',\n borderWidth: 0,\n borderStyle: 'none',\n cursor: 'pointer',\n padding: 0,\n textDecoration: 'none',\n ':hover': {\n color: vars.colors.brandSecondaryOrange,\n textDecoration: 'underline',\n },\n },\n]);\n\nexport const panel = sprinkles({\n borderTopLeftRadius: 'none',\n borderTopRightRadius: 'none',\n borderBottomLeftRadius: '2xl',\n borderBottomRightRadius: '2xl',\n paddingX: 6,\n paddingY: 6,\n});\n\nexport const block = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const fullWidth = sprinkles({\n width: 'full',\n});\n\nexport const panelTitle = sprinkles({\n margin: 0,\n fontSize: 'xl',\n fontWeight: 'bold',\n color: 'brandPrimaryRed',\n letterSpacing: 'tight',\n});\n\nexport const footer = sprinkles({\n marginTop: 4,\n});\n\nexport const brandGhostButton = style([\n sprinkles({\n borderColor: 'brandPrimaryRed',\n borderWidth: 'px',\n borderStyle: 'solid',\n color: 'brandPrimaryRed',\n backgroundColor: 'brandLightGray',\n transitionProperty: 'colors',\n transitionDuration: 120,\n transitionTimingFunction: 'ease',\n }),\n {\n selectors: {\n '&:hover:not(:disabled)': {\n backgroundColor: `color-mix(in srgb, ${vars.colors.brandPrimaryRed} 8%, transparent)`,\n color: vars.colors.brandSecondaryOrange,\n borderColor: vars.colors.brandSecondaryOrange,\n },\n },\n },\n]);\n"],"mappings":";;AAGA,SAAgB,IAA0D;AACxE,QAAO,EAAe,SAAS"}
1
+ {"version":3,"file":"loginPage.css-CBJ1Ozm5.js","names":[],"sources":["../../src/i18n/useSharedTranslation.ts","../../src/auth/login/loginPage.css.ts"],"sourcesContent":["import { useTranslation } from 'react-i18next';\n\n/** Returns i18n helpers bound to the shared namespace. */\nexport function useSharedTranslation(): ReturnType<typeof useTranslation> {\n return useTranslation('shared');\n}\n","import { style } from '@vanilla-extract/css';\nimport { sprinkles, vars } from '@plumile/ui';\n\nexport const stack = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const formSurface = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n width: 'full',\n});\n\nexport const helper = sprinkles({\n color: 'brandDarkGray',\n fontSize: 'sm',\n margin: 0,\n lineHeight: 1.6,\n});\n\nexport const divider = sprinkles({\n alignItems: 'center',\n color: 'brandDarkGray',\n display: 'flex',\n gap: 2,\n marginTop: 5,\n marginBottom: 3,\n});\n\nexport const dividerLine = sprinkles({\n backgroundColor: 'brandPrimaryRed',\n height: 'px',\n flex: 1,\n borderRadius: 'full',\n opacity: 35,\n});\n\nexport const actionsRow = sprinkles({\n alignItems: 'center',\n display: 'flex',\n flexWrap: 'wrap',\n gap: 3,\n justifyContent: 'space-between',\n marginTop: 3,\n});\n\nexport const inlineLink = style([\n sprinkles({\n color: 'brandPrimaryRed',\n fontWeight: 'semibold',\n transitionProperty: 'colors',\n transitionDuration: 150,\n transitionTimingFunction: 'ease',\n }),\n {\n background: 'transparent',\n borderWidth: 0,\n borderStyle: 'none',\n cursor: 'pointer',\n padding: 0,\n textDecoration: 'none',\n ':hover': {\n color: vars.colors.brandSecondaryOrange,\n textDecoration: 'underline',\n },\n },\n]);\n\nexport const panel = sprinkles({\n borderTopLeftRadius: 'none',\n borderTopRightRadius: 'none',\n borderBottomLeftRadius: '2xl',\n borderBottomRightRadius: '2xl',\n paddingX: 6,\n paddingY: 6,\n});\n\nexport const block = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const fullWidth = sprinkles({\n width: 'full',\n});\n\nexport const panelTitle = sprinkles({\n margin: 0,\n fontSize: 'xl',\n fontWeight: 'bold',\n color: 'brandPrimaryRed',\n letterSpacing: 'tight',\n});\n\nexport const footer = sprinkles({\n marginTop: 4,\n});\n\nexport const brandGhostButton = style([\n sprinkles({\n borderColor: 'brandPrimaryRed',\n borderWidth: 'px',\n borderStyle: 'solid',\n color: 'brandPrimaryRed',\n backgroundColor: 'brandLightGray',\n transitionProperty: 'colors',\n transitionDuration: 120,\n transitionTimingFunction: 'ease',\n }),\n {\n selectors: {\n '&:hover:not(:disabled)': {\n backgroundColor: `color-mix(in srgb, ${vars.colors.brandPrimaryRed} 8%, transparent)`,\n color: vars.colors.brandSecondaryOrange,\n borderColor: vars.colors.brandSecondaryOrange,\n },\n },\n },\n]);\n"],"mappings":";;AAGA,SAAgB,IAA0D;AACxE,QAAO,EAAe,SAAS"}
@@ -1,6 +1,6 @@
1
- import { a as e, c as t, d as n, f as r, o as i, r as a, s as o, t as s } from "./loginPage.css-4M4PrzUn.js";
2
- import { o as c } from "./useAuth-tQWc1NnB.js";
3
- import { t as l } from "./AuthPanel-Co626p7A.js";
1
+ import { a as e, c as t, d as n, f as r, o as i, r as a, s as o, t as s } from "./loginPage.css-CBJ1Ozm5.js";
2
+ import { o as c } from "./useAuth-CjdysxLB.js";
3
+ import { t as l } from "./AuthPanel-DiHejPoq.js";
4
4
  import { useCallback as u, useEffect as d, useMemo as f, useRef as p, useState as m } from "react";
5
5
  import { Trans as h } from "react-i18next";
6
6
  import { AuthLayout as g, Button as _, FormError as v, FormField as y, LoginForm as b, cx as x } from "@plumile/ui";
@@ -320,4 +320,4 @@ async function N(e, t) {
320
320
  //#endregion
321
321
  export { j as n, N as t };
322
322
 
323
- //# sourceMappingURL=synchronizeAuthStatusQuery-Bb5wh5rF.js.map
323
+ //# sourceMappingURL=synchronizeAuthStatusQuery-Dr6AEFhi.js.map