pageHelpers.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import { searchPath } from "@/lib/frontend/routes";
  2. import {
  3. serializeSearchUrlState,
  4. SEARCH_SCOPE,
  5. } from "@/lib/frontend/search/urlState";
  6. import { isValidBranchParam } from "@/lib/frontend/params";
  7. /**
  8. * Build the full /:branch/search href for a given state.
  9. *
  10. * @param {{ routeBranch: string, state: any }} input
  11. * @returns {string}
  12. */
  13. export function buildSearchHref({ routeBranch, state }) {
  14. const base = searchPath(routeBranch);
  15. const qs = serializeSearchUrlState(state);
  16. return qs ? `${base}?${qs}` : base;
  17. }
  18. /**
  19. * Build a stable searchKey identity (cursor excluded).
  20. * Includes routeBranch to avoid cross-branch race conditions.
  21. *
  22. * @param {{ routeBranch: string, urlState: any }} input
  23. * @returns {string}
  24. */
  25. export function buildSearchKey({ routeBranch, urlState }) {
  26. const qs = serializeSearchUrlState(urlState);
  27. return `${routeBranch}|${qs}`;
  28. }
  29. /**
  30. * Derive the results description label for the current scope.
  31. *
  32. * @param {{ routeBranch: string, urlState: any }} input
  33. * @returns {string}
  34. */
  35. export function getScopeLabel({ routeBranch, urlState }) {
  36. const multiCount = Array.isArray(urlState?.branches)
  37. ? urlState.branches.length
  38. : 0;
  39. if (urlState?.scope === SEARCH_SCOPE.ALL) return "Alle Niederlassungen";
  40. if (urlState?.scope === SEARCH_SCOPE.MULTI) {
  41. if (multiCount > 0) {
  42. return `${multiCount} Niederlassung${multiCount === 1 ? "" : "en"}`;
  43. }
  44. return "Mehrere Niederlassungen";
  45. }
  46. return `Niederlassung ${routeBranch}`;
  47. }
  48. /**
  49. * Whether the UI should show the "select at least one branch" hint.
  50. *
  51. * @param {{ isAdminDev: boolean, urlState: any }} input
  52. * @returns {boolean}
  53. */
  54. export function needsMultiBranchSelectionHint({ isAdminDev, urlState }) {
  55. const multiCount = Array.isArray(urlState?.branches)
  56. ? urlState.branches.length
  57. : 0;
  58. return (
  59. Boolean(isAdminDev) &&
  60. urlState?.scope === SEARCH_SCOPE.MULTI &&
  61. Boolean(urlState?.q) &&
  62. multiCount === 0
  63. );
  64. }
  65. /**
  66. * Build the next state for scope changes.
  67. *
  68. * @param {{ urlState: any, nextScope: string }} input
  69. * @returns {any}
  70. */
  71. export function buildNextStateForScopeChange({ urlState, nextScope }) {
  72. return {
  73. ...urlState,
  74. scope: nextScope,
  75. branches: nextScope === SEARCH_SCOPE.MULTI ? urlState.branches : [],
  76. };
  77. }
  78. /**
  79. * Toggle one branch in MULTI mode.
  80. *
  81. * @param {{ urlState: any, branchId: string }} input
  82. * @returns {any}
  83. */
  84. export function buildNextStateForToggleBranch({ urlState, branchId }) {
  85. const current = Array.isArray(urlState?.branches) ? urlState.branches : [];
  86. const set = new Set(current);
  87. if (set.has(branchId)) set.delete(branchId);
  88. else set.add(branchId);
  89. return {
  90. ...urlState,
  91. scope: SEARCH_SCOPE.MULTI,
  92. branches: Array.from(set),
  93. };
  94. }
  95. /**
  96. * Clear all branches in MULTI mode.
  97. *
  98. * @param {{ urlState: any }} input
  99. * @returns {any}
  100. */
  101. export function buildNextStateForClearAllBranches({ urlState }) {
  102. return {
  103. ...urlState,
  104. scope: SEARCH_SCOPE.MULTI,
  105. branches: [],
  106. };
  107. }
  108. /**
  109. * Build a navigation target for switching SINGLE branch (path segment).
  110. *
  111. * @param {{ nextBranch: string, urlState: any }} input
  112. * @returns {string|null}
  113. */
  114. export function buildHrefForSingleBranchSwitch({ nextBranch, urlState }) {
  115. if (!isValidBranchParam(nextBranch)) return null;
  116. const nextState = {
  117. ...urlState,
  118. scope: SEARCH_SCOPE.SINGLE,
  119. branches: [],
  120. };
  121. return buildSearchHref({ routeBranch: nextBranch, state: nextState });
  122. }