Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

136 linhas
3.3KB

  1. import { cloneDeep, isEqual, unset } from "lodash";
  2. import { ReactNode, createContext, useEffect, useMemo, useState } from "react";
  3. // form
  4. import { useLocation } from "react-router";
  5. import { Dictionary } from "@types";
  6. import useNavigateCustom from "hooks/useNavigateCustom";
  7. // ----------------------------------------------------------------------
  8. const _condition: Dictionary = {};
  9. const initialState = {
  10. initialized: false,
  11. condition: _condition,
  12. get: (key: string): string => "",
  13. initializeCondition: () => {},
  14. addCondition: (condition: Dictionary) => {
  15. console.log("not init SearchConditionContext");
  16. },
  17. clearCondition: () => {},
  18. };
  19. export const SearchConditionContext = createContext(initialState);
  20. type Props = {
  21. children: ReactNode;
  22. };
  23. export function SearchConditionContextProvider({ children }: Props) {
  24. const [condition, _setCondition] = useState<Dictionary>({});
  25. const [initialized, setInitialized] = useState(false);
  26. const { pathname, search } = useLocation();
  27. const { navigateWhenChanged } = useNavigateCustom();
  28. const setCondition = (after: Dictionary, message?: any) => {
  29. if (message) {
  30. console.log("Contidion Change", { after, message });
  31. }
  32. _setCondition(after);
  33. };
  34. const initializeCondition = () => {
  35. const after: Dictionary = {};
  36. const urlParam = new URLSearchParams(search);
  37. for (const [key, value] of urlParam.entries()) {
  38. after[key] = value;
  39. }
  40. if (!isEqual(after, condition)) {
  41. setCondition(after, "initializeCondition");
  42. }
  43. setInitialized(true);
  44. };
  45. const get = (key: string) => {
  46. return condition[key] ?? "";
  47. };
  48. const getCondition = useMemo(() => {
  49. return cloneDeep(condition);
  50. }, [condition]);
  51. const addCondition = (additional: Dictionary) => {
  52. if (!initialized) return;
  53. const before = cloneDeep(condition);
  54. const after = cloneDeep(condition);
  55. Object.keys(additional).forEach((key) => {
  56. unset(after, key);
  57. if (additional[key] !== "") {
  58. after[key] = additional[key];
  59. }
  60. });
  61. // console.log("compare condition", {
  62. // before,
  63. // after,
  64. // });
  65. if (!isEqual(before, after)) {
  66. // console.log("add condition", {
  67. // before,
  68. // after,
  69. // });
  70. setCondition(after, "addCondition");
  71. }
  72. };
  73. const searchParams = useMemo(() => {
  74. const params = new URLSearchParams();
  75. if (!initialized) return params;
  76. Object.keys(condition).forEach((key) => {
  77. params.append(key, condition[key]);
  78. });
  79. params.sort();
  80. return params;
  81. }, [condition]);
  82. const applyToURL = () => {
  83. if (!initialized) return;
  84. navigateWhenChanged(pathname, condition, "applyToURL");
  85. };
  86. const clearCondition = () => {
  87. setCondition({}, "clearCondition");
  88. setInitialized(false);
  89. };
  90. useEffect(() => {
  91. if (initialized) {
  92. // console.log("call applyToURL", { condition, initialized });
  93. applyToURL();
  94. }
  95. }, [condition, initialized]);
  96. useEffect(() => {
  97. initializeCondition();
  98. }, [pathname, search]);
  99. return (
  100. <SearchConditionContext.Provider
  101. value={{
  102. condition: getCondition,
  103. initialized,
  104. get,
  105. initializeCondition,
  106. addCondition,
  107. clearCondition,
  108. }}
  109. >
  110. {children}
  111. </SearchConditionContext.Provider>
  112. );
  113. }